Compare commits

...

505 Commits

Author SHA1 Message Date
openvela-robot 81bfb81dc7 update workflow files 2026-02-02 19:42:26 +08:00
openvela-robot ab059a1a6f update .github 2026-01-04 10:59:19 +08:00
openvela-robot 4d574f5114 update .github 2026-01-04 10:59:19 +08:00
openvela-robot 27eaec3a64 update workflows ci.yml, delete pull_request_review trigger 2026-01-04 10:59:19 +08:00
openvela-robot da7dce2276 add .github/CODEOWNERS PULL_REQUEST_TEMPLATE.md 2026-01-04 10:59:19 +08:00
liujinye f168d0a538 delete gdbus 2025-12-29 13:18:48 +08:00
openvela-robot 11f44f733a add .github .gitee 2025-12-17 01:21:36 +08:00
yintao 6b596e4ff5 kvdb: Set the maximum listening count for kvdb separately
kvdbd is single threaded.
If CP calls property_list, AP'S kvdbd will continue to send to cp,
then accept will not be executed.
If another thread at CP loops to call property_set,
the AP server-side's pending queue will be full and reject next connection.

Bluetooth now loops through 15 times to call 'property_set',
So to avoid rejecting the connection,
set a macro to separately manage the listening count of kvdb

Signed-off-by: yintao <yintao@xiaomi.com>
2025-12-15 18:24:20 +08:00
ligd 9d294a428a kvdb: enhance server fault tolerance
When server recv msg header, there maybe recv only one byte.
Then we should continue the full header use kvdb_recv()

Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:20 +08:00
zhangbo56 5b2a21530c kvdb: Support kvdb server identified by device
Should be passed from device specific setting.

Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:20 +08:00
zhangbo56 33af11c421 kvdb: Export include/utils to other android module
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:20 +08:00
zhangbo56 4e1f285645 kvdb: Add kernel module headers to kvdb build
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:20 +08:00
huangcaihua b14b9c389c gdbus:Fix coverty for check return of asprintf
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:20 +08:00
huangcaihua e2311361b8 Fix coverity for return value check
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:20 +08:00
huangcaihua fc8cd0c944 Fix coverity for mistake free dbus watcher
Only free just alloced data variable here. No need call filter_data_free which maybe free watcher.

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:20 +08:00
huangcaihua 8617569b6b Fix coverity for FORWARD_NULL
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:20 +08:00
huangcaihua e5b7998e75 gdbus:Add new gdbus config with depend on uv-ext
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua 81bf130027 Fix: Compile warning and memory leak
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua ba9f08a713 refactor object file for open vela
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua a7d2c908d3 refactor watch file for open source
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua 68316d5269 refactor polkit file for open source
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
hongfengchen 78c43330e9 utils:KVDB_NVS should depend on MTD_CONFIG_NAMED
KVDB_NVS should depend on MTD_CONFIG_NAMED. If choose
select MTD_CONFIG_NAMED and CONFIG_MTD is not set, it
will lead to compile error like:

dev-system/nuttx/include/nuttx/mtd/configdata.h:79:20: error: 'CONFIG_MTD_CONFIG_NAME_LEN' undeclared here (not in a function); did you mean 'CONFIG_MTD_CONFIG_NAMED'?
   79 |   char        name[CONFIG_MTD_CONFIG_NAME_LEN];
      |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
      |                    CONFIG_MTD_CONFIG_NAMED

Signed-off-by: hongfengchen <hongfengchen@xiaomi.com>
2025-12-15 18:24:19 +08:00
wangxuedong ac19b907f1 kvdb: add retry if recv's errno is EAGAIN
Signed-off-by: wangxuedong <wangxuedong@xiaomi.com>
2025-12-15 18:24:19 +08:00
wushenhui 56d9f4f858 utils/kvdb: fix build error when CONFIG_NET_LOCAL not set and CONFIG_NET_RPMSG=y
Signed-off-by: wushenhui <wushenhui@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua 74b75590cb GDBus:Set DBUS_TIMEOUT_INFINITE timer that is no dbus timeout
No need add reply timer for async method call.
if set -1, that is dbus default timer(25s).

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua b1bb85ad39 revert debug assert for method call no reply.
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua 22572fa2f1 GDBus:No need add reply timer for async method call
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua fc535ac9a7 Fix:Get New Added proxy proper need add getting_all_prop flag
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
huangcaihua 7a94a96240 Fix:gdbus notify proxy_added after proxy all properties got.
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:19 +08:00
zhangyu117 dad95e2787 frameworks/system: Fix some minor issues when features on specific product-dev are switched to dev-system
Signed-off-by: zhangyu117 <zhangyu117@xiaomi.com>
2025-12-15 18:24:19 +08:00
zhangbo56 8c2b7f8a4e kvdb: Add more apis for kvdb handle error case
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:19 +08:00
yukangzhi fd01781f55 frameworks/system/utils: Resolve compilation warnings
clang-format the file include/cutils/trace.h

"/home/mi/workspace_vela/nuttx/../apps/frameworks/
system/utils/include/cutils/trace.h", line 154: warning #1731-D:
          function must be declared at file scope
          void atrace_begin_body(const char*);
               ^
"/home/mi/workspace_vela/nuttx/../apps/frameworks/
system/utils/include/cutils/trace.h", line 167: warning #1731-D:
          function must be declared at file scope
          void atrace_end_body(void);
               ^
"/home/mi/workspace_vela/nuttx/../apps/frameworks/
system/utils/include/cutils/trace.h", line 185: warning #1731-D:
          function must be declared at file scope
          void atrace_async_begin_body(const char*, int32_t);
               ^
"/home/mi/workspace_vela/nuttx/../apps/frameworks/
system/utils/include/cutils/trace.h", line 198: warning #1731-D:
          function must be declared at file scope
          void atrace_async_end_body(const char*, int32_t);
               ^

Signed-off-by: yukangzhi <yukangzhi@xiaomi.com>
2025-12-15 18:24:19 +08:00
daichuan ed778af5a9 add for the vendor partition code can use kvdb
Signed-off-by: daichuan <daichuan@xiaomi.com>
2025-12-15 18:24:19 +08:00
zhangbo56 4ec33c844e trace: Default enable trace.c compile
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:19 +08:00
zhaoxingyu1 4c070d84b0 framework/kvdb: modify kvdb depends on !MTD_CONFIG_NONE
Signed-off-by: zhaoxingyu1 <zhaoxingyu1@xiaomi.com>
2025-12-15 18:24:19 +08:00
hongfengchen dc15b3f58b change murmurhash to static inline
Change murmurhash to static inline.

Signed-off-by: hongfengchen <hongfengchen@xiaomi.com>
2025-12-15 18:24:18 +08:00
hongfengchen 3a898cb303 utils:add unistd.h
Add unistd.h for files in kvdb and log.

Signed-off-by: hongfengchen <hongfengchen@xiaomi.com>
2025-12-15 18:24:18 +08:00
hongfengchen 78f2846dd1 add murmurhash function
Add murmurhash function to map a string to hash int.

Signed-off-by: hongfengchen <hongfengchen@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua 659b244934 Fix:Coverity for spurious wakeup and null check_after_deref
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua 1da41823bb Fix:GDbus get prop sync from default loop
GDbus cache the proxy properties, for multi-thread, one thread gets
prop value which maybe freed by default loop thread.

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
xujianhang f96515434f gdbus: Resolve the Bluetooth module's failure to acquire the oFono NetworkOperator service
Signed-off-by: xujianhang <xujianhang@xiaomi.com>
2025-12-15 18:24:18 +08:00
guohao15 daf0204ba9 kvdb:dump more information when API failed
Signed-off-by: guohao15 <guohao15@xiaomi.com>
2025-12-15 18:24:18 +08:00
ligd 749a14fb69 kvdb/server: check space before monitor notify to avoid deadlock
Deadlock:
kvdbd                      client
                           poll monitor
monitor notify
                           recv notify
monitor notify
monitor notify
...
monitor notify
monitor notify
                           property_get() //wait kvdb reponse
monitor notify
//send buf full

Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua d0dbef6f1d Fix: remove signal filter when receive dbus disconnect msg
If the dbus disconnect message has been received,
it means that the current dbus connection is invalid.
The added disconnect message signal filter also needs to be free.

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua 3362b52de2 Fix: Not get all proxy properties when any interface added
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
wenlingyun1 586a2cda63 kvdb/cmake: add command qemuprop
Signed-off-by: wenlingyun1 <wenlingyun1@xiaomi.com>
2025-12-15 18:24:18 +08:00
zhangshoukui f28493904c KVDB_NVS: modify depends on
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:18 +08:00
zhangshoukui 032f1f858f rename property_reload to property_load and Support for passing parameters
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua b22c42a889 Fix:Add user_data for gdbus callback filter.
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
huangcaihua 01dde63642 Fix: Must free client queue handle in async queue close callback func
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:18 +08:00
cuiziwei 1d221149c8 ALOG: Fixed the issue that disable ALOG will print ANDROID_LOG_VERBOSE level logs by default.
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:18 +08:00
cuiziwei a2858e3dfc 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-12-15 18:24:18 +08:00
xuxin19 0701595849 cmake(bugfix):add missing kvdb exitprop cmake build
Signed-off-by: xuxin19 <xuxin19@xiaomi.com>
2025-12-15 18:24:18 +08:00
buxiasen a274cb1651 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-12-15 18:24:17 +08:00
chenrun1 43e35964c3 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

dependson:756874

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2025-12-15 18:24:17 +08:00
wangmingrong1 c9d0c2f82d Open source transformation
Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
2025-12-15 18:24:17 +08:00
zhangshoukui 0974feba8e fix compile warning
kvdb/getprop.c:60:9: error: call to undeclared function 'callback'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]

Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:17 +08:00
huangcaihua cfb155730d Fix:Cancel pendingcall when received interface remove message
Gdbus will get properties when received interface add message,
If not cancel the getting properties pendingcall, it maybe use
freed proxy which will be freed after received interface remove message.

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:17 +08:00
huangcaihua 340bd6613e Fix:use async queue API to close async-queue handler
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:17 +08:00
Shanmin Zhang cfda376446 goldfish: convert from qemu.sf.lcd_density to ro.sf.lcd_density
Signed-off-by: Shanmin Zhang <zhangshanmin@xiaomi.com>
2025-12-15 18:24:17 +08:00
Shanmin Zhang 1b0af71102 goldfish: support heartbeat and bootcomplete message.
Signed-off-by: Shanmin Zhang <zhangshanmin@xiaomi.com>
2025-12-15 18:24:17 +08:00
huangcaihua 870af45893 Fix:Add assert when recieve dbus NoReply Error
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:17 +08:00
chenrun1 4057b8981f filekv: add trunk mode when setprop
Summary:
Add O_TRUNC flags in kvdb_file_set, avoid when the first set value is greater than the second overwrite, actual value is wrong

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2025-12-15 18:24:17 +08:00
zhangshoukui 87e7aeb429 Fixed garbled characters displayed on binary keys
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:17 +08:00
chenrun1 3d293393c5 unqlite.c:Add value_len to avoid causing a memory stampede
Summary:
  In the unqlite api, unqlite_kv_fetch must use parameters
1. kvdb handler
2. key
3. key_len
4. value_len
This problem is because when value_len is not provided, the content is assigned to the 0x0 address, which causes the dataabort caught by Kasan

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2025-12-15 18:24:17 +08:00
guoshichao 52f0b2de34 system/utils: fix the inaccurate descriptions in the document
Signed-off-by: guoshichao <guoshichao@xiaomi.com>
2025-12-15 18:24:17 +08:00
huangcaihua 89180702ef Fix: gdbus async send dbus message reply
dbus_connection_send_with_reply returned pendingcall object, then set pendingcall notify function.
When dbus reply, it will call dbus pendingcall handle process, and call notify fuction.
For both thread, ensure that the dbus pendingcall notify is set to execute first, and then execute the dbus reply call notify pendingcall process

Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:17 +08:00
xuxin19 a64bdce895 utils(build):refactor frameworks system build
Signed-off-by: xuxin19 <xuxin19@xiaomi.com>
2025-12-15 18:24:17 +08:00
yintao 1b3ed4a5ac kvdb: add retry to avoid kvdb not being started
connect will return ENOENT if kvdb server not being started when use local socket
so client need to retry connect until kvdb server is listening.

Signed-off-by: yintao <yintao@xiaomi.com>
2025-12-15 18:24:17 +08:00
Shanmin Zhang 46435e4b40 goldfish: add qemu-props for passing boot properties.
Signed-off-by: Shanmin Zhang <zhangshanmin@xiaomi.com>
2025-12-15 18:24:17 +08:00
huangcaihua e3ce03e6ad Fix: Add gdbus API comment
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:17 +08:00
guoshichao 13481a4cd5 framework/utils: add the intro doc and api doc
Signed-off-by: guoshichao <guoshichao@xiaomi.com>
2025-12-15 18:24:17 +08:00
buxiasen 2b334c10d7 kvdb/file: fix typeo in list
Signed-off-by: buxiasen <buxiasen@xiaomi.com>
2025-12-15 18:24:17 +08:00
zhangbo56 d2b17914ed kvdb: Fix a build break in Android
Add types header.

Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:16 +08:00
chenrun1 de90faf2e7 kvdb/file.c:Fix overflow return value
Summary:
  1.Change the type of nbyteswrite to size_t
  2.close(dir) before return

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangshoukui 5628656716 Fix compile error
kvdb/client.c: In function 'property_get_binary':
kvdb/client.c:305:29: error: 'len' may be used uninitialized [-Werror=maybe-uninitialized] kvdb/client.c:277:13: note: 'len' was declared here cc1: all warnings being treated as errors

Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangshoukui 042d7d9f36 kvdb_file_get failed should close dir
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangshoukui ad8d2597e6 kvdb: Support storage binary value
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:16 +08:00
dongjiuzhu1 0e595320ab kvdb/server: wait until filesystem mount success or timeout 20ms
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:16 +08:00
chenrun1 b3f60356d8 kvdb/file: Add new optional kvdb backend filekv
Summary:
  Added filekv backend,We need to configure the persist storage location (folder directory) and tmp storage location (folder directory) if we need
  next:Put the file behavior in common so that other backends can use it

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
Signed-off-by: buxiasen <buxiasen@xiaomi.com>
2025-12-15 18:24:16 +08:00
guohao15 5a6ae3f70a kvdb:add new Kconfig to minimize code size
Signed-off-by: guohao15 <guohao15@xiaomi.com>
Signed-off-by: buxiasen <buxiasen@xiaomi.com>
2025-12-15 18:24:16 +08:00
dongjiuzhu1 d1f6afe13a frameworks/kvdb: fix minor issue about set_int64_oneway
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:16 +08:00
haopengxiang 32f6cc0549 utils/kvdb/Kconfig: simplify KVDB_UNQLITE depends on
FS_LOCK_BUCKET_SIZE has been added required in config UNQLITE

config UNQLITE
	bool "UnQLite Database"
	depends on TLS_TASK_NELEM > 0
	depends on FS_LOCK_BUCKET_SIZE > 0
	default n

Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangbo56 301998ea83 kvdb: Modify android build get/set prop name
1. Set name to kvset/kvget.
2. Move from vendor partition to system partition.

Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangbo56 e842fa444a kvdb: Fix a get int32/int64 with empty key error case
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:16 +08:00
zhangbo56 85de640853 kvdb: export kvdb header path for jni use
Signed-off-by: zhangbo56 <zhangbo56@xiaomi.com>
2025-12-15 18:24:16 +08:00
xujianhang d959b76294 frameworks/utils: adjust the code style of log_radio.h to WebKit
Signed-off-by: xujianhang <xujianhang@xiaomi.com>
2025-12-15 18:24:16 +08:00
haopengxiang 2d72c6a7ce frameworks/utils/Makefile: update utils to libutils.a for opt soruce to partner env
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:16 +08:00
xujianhang ec9aa1794c frameworks/utils: allow printing non-debug logs
Signed-off-by: xujianhang <xujianhang@xiaomi.com>
2025-12-15 18:24:16 +08:00
dongjiuzhu1 39e08271d4 frameworks/kvdb: add error log about open failed
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:16 +08:00
xujianhang 3a8a321d4e frameworks/utils: add a switch for ril log
Signed-off-by: xujianhang <xujianhang@xiaomi.com>
2025-12-15 18:24:16 +08:00
xujianhang bdf531019c frameworks/gdbus: fix the bug where method_call_reply is not executed probailistically
When the dbus message returns too quickly, the dbus message may return
before dbus_pending_call_set_notify is executed, resulting in the
callback function not being executed.

Signed-off-by: xujianhang <xujianhang@xiaomi.com>
2025-12-15 18:24:16 +08:00
huangcaihua ca9e7d624c Fix: Add return false check for coverit
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:16 +08:00
liwenxiang1 98afab50c0 utils/kvdb:kvdb_bind adds CONFIG_NET_RPMSG to configure RPMSG server
Open RPMSG configuration to enable RPMSG server, otherwise it will fail to test

Signed-off-by: liwenxiang1 <liwenxiang1@xiaomi.com>
2025-12-15 18:24:15 +08:00
huangcaihua 60c38e022f Fix: remove if null condition that won't be null
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:15 +08:00
dongjiuzhu1 589b535c75 kvdb/server: wait until filesystem mount success
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:15 +08:00
huangcaihua bbf0241519 Fix: Change code to WebKit style
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:15 +08:00
guohao15 351f0454c8 add propset/propget for Android
Signed-off-by: guohao15 <guohao15@xiaomi.com>
2025-12-15 18:24:15 +08:00
huangcaihua ecb3d6bed5 Fix:gDBus support interface to filter proxy
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:15 +08:00
zhangshoukui a07e973574 kvdb unqlite: supports the creation of ro properties, which cannot be modified
Signed-off-by: zhangshoukui <zhangshoukui@xiaomi.com>
2025-12-15 18:24:15 +08:00
cuiziwei 5a83196f1d sim/m64:Fix build warning.
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:15 +08:00
likun17 c315121abf log_write.c:Adapt the new header file path of va_format.
Signed-off-by: likun17 <likun17@xiaomi.com>
2025-12-15 18:24:15 +08:00
zhanghongyu 43e1c9b33a frameworks/utils: fix cmake build error
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
2025-12-15 18:24:15 +08:00
xuxin19 cad5f9a52a Makefile:add compile CONFIG conditions for frameworks utils
Signed-off-by: xuxin19 <xuxin19@xiaomi.com>
2025-12-15 18:24:15 +08:00
xuxin19 0d07b93011 cmake:add framework utils cmake build
Signed-off-by: xuxin19 <xuxin19@xiaomi.com>
2025-12-15 18:24:15 +08:00
Shoukui Zhang 256d0a4f1f kvdb: Add kvdb depends and configuration help
Signed-off-by: Shoukui Zhang <zhangshoukui@xiaomi.com>
2025-12-15 18:24:15 +08:00
huangcaihua 38fdc66612 Fix: Filter can handle empty dbus signal message without crashing
Signed-off-by: huangcaihua <huangcaihua@xiaomi.com>
2025-12-15 18:24:15 +08:00
wangjianyu3 837fcbb4b5 kvdb: More log for property_commit()
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2025-12-15 18:24:15 +08:00
wangjianyu3 50dd8937e9 kvdb/setprop: Check return value of property_commit()
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2025-12-15 18:24:15 +08:00
wangjianyu3 780614cd9d kvdb: property_commit() waits for kvdb_commit() to complete by default
Signed-off-by: wangjianyu3 <wangjianyu3@xiaomi.com>
2025-12-15 18:24:15 +08:00
xucheng5 2fc25fcc54 kvdb: support config non-persist key-value
dependson:odm_473531 odm_474320

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:15 +08:00
wangmingrong 5d95e3a9d2 kvdb: adjustment code
kvdb_load moved from command. c to server. c

Signed-off-by: wangmingrong <wangmingrong@xiaomi.com>
2025-12-15 18:24:15 +08:00
wanggang26 c6900c902d kvdb: enable O_CLOEXEC explicit
Signed-off-by: wanggang26 <wanggang26@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 3da2f6b4d5 framework/kvdb : optimizate the code
multi definiation for KVDB_MEM , KVDB_COUNT .etc

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 dec3c49ca4 gdbs/pendingcall: Checks whether the pending call has received
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 c36fb62273 kvdb/direct: property_get return the len which not include '\0'
should be the same with server mode

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
Bowen Wang abbbffa922 kvdb/server: fix the monitor bug
VELAPLATFO-10160:VELAPLATFO-10831

This bug is introduced by:
https://gerrit.pt.mioffice.cn/c/vela/frameworks/utils/+/3080162

Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 8837aa44bd framework/kvdb : fixed build error
Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 38c863df46 framwork/kvdb: PROP_MSG use heap instead of stack
reduce stack size of getprop/setprop/kvdbd

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 3a75d71df9 kvdb/nvs : 'persist.' prefix auto convert when store
Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 53bf3e7fd8 kvdb/nvs : fixed kvdb list error
configdata should be valid

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 741932da37 gdbus/mainloop: fix memory leak
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
cuiziwei ca08b62bfc frameworks/utils:fix build warning.
binder/Binder.cpp: In member function ‘android::status_t android::BBinder::setRpcClientDebug(android::base::unique_fd, const android::sp<android::IBinder>&)’:
binder/Binder.cpp:529:15: warning: unused variable ‘socketFdForPrint’ [-Wunused-variable]
  529 |     const int socketFdForPrint = socketFd.get();
      |               ^~~~~~~~~~~~~~~~
binder/BpBinder.cpp: In member function ‘void android::BpBinder::ObjectManager::kill()’:
binder/BpBinder.cpp:103:18: warning: unused variable ‘N’ [-Wunused-variable]
  103 |     const size_t N = mObjects.size();
      |                  ^
CC:  vfs/fs_timerfd.c binder/IMemory.cpp: In member function ‘void android::HeapCache::dump_heaps()’:
binder/IMemory.cpp:508:29: warning: unused variable ‘h’ [-Wunused-variable]
  508 |         BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
      |                             ^
binder/RpcServer.cpp: In static member function ‘static void android::RpcServer::establishConnection(android::sp<android::RpcServer>&&, android::base::unique_fd, sockaddr_storage, socklen_t)’:
binder/RpcServer.cpp:286:9: warning: unused variable ‘clientFdForLog’ [-Wunused-variable]
  286 |     int clientFdForLog = clientFd.get();
      |         ^~~~~~~~~~~~~~
CC:  netdb/lib_dnsbind.c binder/RpcState.cpp: In member function ‘void android::RpcState::dumpLocked()’:
binder/RpcState.cpp:269:21: warning: variable ‘desc’ set but not used [-Wunused-but-set-variable]
  269 |         const char* desc;
      |                     ^~~~

Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:14 +08:00
cuiziwei f0787a21ef frameworks/utils:modify the macro definition of LOG_ALWAYS_FATAL_IF.
when close the LOG_ALWAYS_FATAL_IF, retain the conditional statement judgment in LOG_ALWAYS_FATAL_IF.

Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:14 +08:00
cuiziwei 8f6f01ae23 framworks/utils:add CONFIG_ALOG to control log level.
Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:14 +08:00
cuiziwei 14307399b1 framworks/utils:fix clang-format warning.
log_main.h:67:40: warning: code should be clang-formatted [-Wclang-format-violations]
constexpr int __fake_use_va_args(Ts...) {
                                       ^
log_main.h:67:42: warning: code should be clang-formatted [-Wclang-format-violations]
constexpr int __fake_use_va_args(Ts...) {
                                         ^
log_main.h:85:41: warning: code should be clang-formatted [-Wclang-format-violations]
                                        ^
log_main.h:88:48: warning: code should be clang-formatted [-Wclang-format-violations]
                                               ^
log_main.h:102:45: warning: code should be clang-formatted [-Wclang-format-violations]
                                            ^
log_main.h:123:44: warning: code should be clang-formatted [-Wclang-format-violations]
                                           ^
log_main.h:124:34: warning: code should be clang-formatted [-Wclang-format-violations]
  __android_log_assert(cond, tag,                               \
                                 ^
log_main.h:125:64: warning: code should be clang-formatted [-Wclang-format-violations]
                       _android_second(0, ##VA_ARGS_, NULL) \
                                                               ^
log_main.h:135:39: warning: code should be clang-formatted [-Wclang-format-violations]
                                      ^
log_main.h:136:63: warning: code should be clang-formatted [-Wclang-format-violations]
  ((_predict_false(cond)) ? (FAKE_USE_VA_ARGS(VA_ARGS_),                            \
                                                              ^
log_main.h:137:90: warning: code should be clang-formatted [-Wclang-format-violations]
                              ((void)android_printAssert(#cond, LOG_TAG, ##_VA_ARGS_))) \
                                                                                         ^
log_main.h:142:30: warning: code should be clang-formatted [-Wclang-format-violations]
                             ^
log_main.h:201:19: warning: code should be clang-formatted [-Wclang-format-violations]
                  ^
log_main.h:202:7: warning: code should be clang-formatted [-Wclang-format-violations]
  do {                               \
      ^
log_main.h:203:37: warning: code should be clang-formatted [-Wclang-format-violations]
    _FAKE_USE_VA_ARGS(VA_ARGS_); \
                                    ^
log_main.h:204:17: warning: code should be clang-formatted [-Wclang-format-violations]
    if (false)

{                     \                 ^ log_main.h:205:28: warning: code should be clang-formatted [-Wclang-format-violations]       __ALOGV(__VA_ARGS__);          \                            ^ log_main.h:206:6: warning: code should be clang-formatted [-Wclang-format-violations]     }
                               \
     ^
log_main.h:217:28: warning: code should be clang-formatted [-Wclang-format-violations]
                           ^
log_main.h:218:27: warning: code should be clang-formatted [-Wclang-format-violations]
  ((__predict_false(cond))                                                                \
                          ^
log_main.h:219:90: warning: code should be clang-formatted [-Wclang-format-violations]
       ? (_FAKE_USE_VA_ARGS(VA_ARGS), (void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS_)) \
                                                                                         ^
log_main.h:232:28: warning: code should be clang-formatted [-Wclang-format-violations]
                           ^
log_main.h:233:27: warning: code should be clang-formatted [-Wclang-format-violations]
  ((__predict_false(cond))                                                              \
                          ^
log_main.h:234:88: warning: code should be clang-formatted [-Wclang-format-violations]
       ? (_FAKE_USE_VA_ARGS(VA_ARGS), (void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS_)) \
                                                                                       ^
log_main.h:246:28: warning: code should be clang-formatted [-Wclang-format-violations]
                           ^
log_main.h:247:27: warning: code should be clang-formatted [-Wclang-format-violations]
  ((__predict_false(cond))                                                             \
                          ^
log_main.h:248:87: warning: code should be clang-formatted [-Wclang-format-violations]
       ? (_FAKE_USE_VA_ARGS(VA_ARGS), (void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS_)) \
                                                                                      ^
log_main.h:260:28: warning: code should be clang-formatted [-Wclang-format-violations]
                           ^
log_main.h:261:27: warning: code should be clang-formatted [-Wclang-format-violations]
  ((__predict_false(cond))                                                             \
                          ^
log_main.h:262:87: warning: code should be clang-formatted [-Wclang-format-violations]
       ? (_FAKE_USE_VA_ARGS(VA_ARGS), (void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS_)) \
                                                                                      ^
log_main.h:274:28: warning: code should be clang-formatted [-Wclang-format-violations]
                           ^
log_main.h:275:27: warning: code should be clang-formatted [-Wclang-format-violations]
  ((__predict_false(cond))                                                              \
                          ^
log_main.h:276:88: warning: code should be clang-formatted [-Wclang-format-violations]
       ? (_FAKE_USE_VA_ARGS(VA_ARGS), (void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS_)) \
                                                                                       ^
log_main.h:368:35: warning: code should be clang-formatted [-Wclang-format-violations]
                                  ^
log_main.h:371:35: warning: code should be clang-formatted [-Wclang-format-violations]
                                  ^

Signed-off-by: cuiziwei <cuiziwei@xiaomi.com>
2025-12-15 18:24:14 +08:00
xucheng5 eb1bcb28b7 KVDB : support NVS
KVDB use unqlite by default. NVS will be another choice

dependson: 965665 965758 partner_22343 partner_22348 partner_22347 partner_22345 partner_22354 partner_22397

Signed-off-by: xucheng5 <xucheng5@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 1f2d4109c8 gdbus/client: fix client->ready() multiple calling issue
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 5d7b8476fd gdbus/client: add dbus_proxy_remove_property_watch to free userdata
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 1c48274b13 gdbus/client: support to control get properties for every proxy
neededby:964476

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
yuanchengcheng 3906389b88 kvdb : kvdb supports the mode without server
In the case of a single core, there is no need to monitor the rpmsg socket, and the client can directly call the interface set and get attributes

Signed-off-by: yuanchengcheng <yuanchengcheng@xiaomi.com>
2025-12-15 18:24:14 +08:00
Xiang Xiao 6cce5b24f1 kvdb: Rename CONFIG_KVDB_LOG_LEVEL_xxx to CONFIG_KVDB_LOG_xxx
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:14 +08:00
dongjiuzhu1 f755596ba2 gdbus/client: fix bug about using stack var save ptr of realloc issue
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:14 +08:00
cuiziwei 42769586a9 Revert "trace: Add atrace_is_ready like android"
This reverts commit 95f13f779aab601f9bc6c857d35bea55b38d146e.

Reason for revert: <CC:  spawn/lib_psa_getstackaddr.c trace/trace.c:25:6: error: conflicting type qualifiers for ‘atrace_is_ready’
   25 | bool atrace_is_ready = true;
      |      ^~~~~~~~~~~~~~~>
2025-12-15 18:24:13 +08:00
Xiang Xiao e84ea52cd1 kvdb: Move the internal macro to internal.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:13 +08:00
Xiang Xiao 1f4cc057d1 trace: Add atrace_is_ready like android
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai 011277f8dd replace "shell $(INCDIR)" to "${INCDIR_PREFIX}
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
Xiang Xiao 63234d6d24 kvdb: Implement __system_property_read and __system_property_get
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:13 +08:00
Xiang Xiao 9a03af414d kvdb: Don't include sys/cdefs.h in system_properties.h since is specific to bionic/newlib
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:13 +08:00
dongjiuzhu1 4ae79fdc0e gdbus/client: call proxy_added() when proxy property parse done.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai 538d155110 cutils/trace: update trace.h
Be consistent with external/android/libcutils/libcutils/include/cutils/trace.h

Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai a0d217d9d5 cutils/trace: add atrace command
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai df25b39a1e utils: Add atrace support
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yuanchengcheng 922929e6ca kvdb : modify the kvdb unqlite backend
Remove database-related operations from the server

Signed-off-by: yuanchengcheng <yuanchengcheng@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai 123016bb6c cutils/properties: remove __has_include in properties.h
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai a711f560cf cutils/trace: remove stdatomic.h in trace.h
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai 7c533cd68c cutils/trace: remove CC_UNLIKELY in trace.h
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
yinshengkai f57701ee79 utils/trace: fix compile warnings
warning: function declaration isn't a prototype [-Wstrict-prototypes]
  141 | void atrace_init();

Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2025-12-15 18:24:13 +08:00
wangbowen6 c52a822b49 kvdb: move error log config to correct place and remove unused kconfig
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:13 +08:00
yintao d5ee442b35 utils/Makefile: adjust for internal and partner build
relese gdbus for partner

Signed-off-by: yintao <yintao@xiaomi.com>
2025-12-15 18:24:13 +08:00
dongjiuzhu1 2b55cb408b framework/gdbus: using libuv replace glib loop
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
Signed-off-by: fangzhenwei <fangzhenwei@xiaomi.com>
2025-12-15 18:24:13 +08:00
dongjiuzhu1 5c8862b1e0 gdbus/client: hold pendingcall when get properites to avoid used after free.
when proxy is removed, proxy_free will cancel this pendcall of proxy to avoid
calling pending_reply_cb after proxy was removed, otherwise it will caused used
after free.

==174637==ERROR: AddressSanitizer: heap-use-after-free on address 0xf507c524 at pc 0x5ada152d bp 0xef013f98 sp 0xef013f88
READ of size 4 at 0xf507c524 thread T0
    #0 0x5ada152c in get_properties_reply_not_standard gdbus/client.c:1271
    #1 0x5ada00b3 in method_call_reply gdbus/client.c:1110
    #2 0x5a527468 in _dbus_pending_call_finish_completion dbus/dbus/dbus-pending-call.c:243
    #3 0x5a4e753d in complete_pending_call_and_unlock dbus/dbus/dbus-connection.c:2332
    #4 0x5a4f39d4 in dbus_connection_dispatch dbus/dbus/dbus-connection.c:4663
    #5 0x5a6d5451 in message_dispatch gdbus/mainloop.c:55
    #6 0x5a644109 in g_idle_dispatch glib/glib/gmain.c:6157
    #7 0x5a6364a3 in g_main_dispatch glib/glib/gmain.c:3477
    #8 0x5a63dbdd in g_main_context_dispatch glib/glib/gmain.c:4195
    #9 0x5a63e6db in g_main_context_iterate glib/glib/gmain.c:4271
    #10 0x5a63f998 in g_main_loop_run glib/glib/gmain.c:4471
    #11 0x5ad2ddda in telephonytool_main /home/mage1/data/specific product_sim_new/frameworks/telephony/telephony_tool.c:4465
    #12 0x58f60272 in nxtask_startup sched/task_startup.c:70
    #13 0x58ef82b8 in nxtask_start task/task_start.c:134

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:12 +08:00
wangbowen6 d59e246ac9 kvdb: add error log in kvdb
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:12 +08:00
yintao 7bb83eb141 utils/gdbus:Fix compile conflict
frameworks/utils/gdbus/polkit.c:139: multiple definition of polkit_check_authorization; /external/ofono/ofono/gdbus/polkit.c:157: first defined here

Signed-off-by: yintao <yintao@xiaomi.com>
2025-12-15 18:24:12 +08:00
yintao cd00843d95 gdbus/watch.c: fix filter_data_call_and_free double free
ERROR: AddressSanitizer: attempting to call malloc_usable_size() for pointer which is not owned
#5 0x59c7dfb4 in filter_data_free gdbus/watch.c:221
    #6 0x59c7f10c in filter_data_call_and_free gdbus/watch.c:324
    #7 0x5aba939a in dbus_remove_all_watches gdbus/watch.c:824
    #8 0x5ab6b274 in tapi_close /home/yintao/ofo/220tele/frameworks/telephony/tapi_manager.c:369
    #9 0x5ab5238e in telephonytool_main /home/yintao/ofo/220tele/frameworks/telephony/telephony_tool.c:3422

Signed-off-by: yintao <yintao@xiaomi.com>
2025-12-15 18:24:12 +08:00
wangbowen6 84cbd352a7 kvdb/server: epoll delete the monitor fd when send error
otherwise, the epoll_wait will failed and busy loop the kvdbd

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:12 +08:00
wangbowen6 6cf17ba1cc kvdb: format client.c and server.c to clang-format
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:12 +08:00
qinwei1 6af0b987fa frameworks: utils: add miss function for binder porting
Summary:
   add __android_log_error_write function for binder porting

Signed-off-by: qinwei1 <qinwei1@xiaomi.com>
2025-12-15 18:24:12 +08:00
haopengxiang 3854b4a7f4 utils/Makefile: adjust for internal and partner build
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:12 +08:00
fangzhenwei 6857500e2f gdbus: move gdbus.h to utils/gdbus folder
neededby:904087

Signed-off-by: fangzhenwei <fangzhenwei@xiaomi.com>
2025-12-15 18:24:12 +08:00
wangbowen6 2b5bcd4b18 log/log_write: add android log system wrapper layer
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:12 +08:00
Xiang Xiao 6f4746bc49 kvdb: Fix typo error
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:12 +08:00
Xiang Xiao 9c24729a48 Move kvdb from kvdb/ to utils/kvdb/
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:12 +08:00
openvela-robot acdd224a19 Merge branch 'dev' of kvdb into dev 2025-12-15 18:24:12 +08:00
openvela-robot 77a691d476 init kvdb
Signed-off-by: zhangning21 <zhangning21@xiaomi.com>
2025-12-15 18:24:12 +08:00
openvela-robot 99415b2b1c Remove __INTRODUCED_IN from android/set_abort_message.h
since it is Android specific version not suitable for vela at all

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:12 +08:00
Xiang Xiao 56592a57bf Move NuttX special funcion to kvdb.h
and sync properties.h with Android 13

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:11 +08:00
openvela-robot 8c65ef7f65 Move PROP_NAME_MAX and PROP_VALUE_MAX to system_properties.h
and sync system_properties.h with android 13

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:11 +08:00
openvela-robot b572ba5216 frameworks/gdbus: fix kasan report error because stack var overflow
When the type of basic value is double, can't using void *value as buffer to get value.

==3263760==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xefe13c30 at pc 0x577c0356 bp 0xefe139b8 sp 0xefe139a8
WRITE of size 8 at 0xefe13c30 thread T0
    #0 0x577c0355 in _dbus_marshal_read_basic dbus/dbus/dbus-marshal-basic.c:581
    #1 0x5783bedb in _dbus_type_reader_read_basic dbus/dbus/dbus-marshal-recursive.c:879
    #2 0x5776ef72 in dbus_message_iter_get_basic dbus/dbus/dbus-message.c:2376
    #3 0x57e06daa in iter_append_iter gdbus/client.c:222
    #4 0x57e070b1 in prop_entry_update gdbus/client.c:265
    #5 0x57e07454 in prop_entry_new gdbus/client.c:286
    #6 0x57e0793a in add_property gdbus/client.c:322
    #7 0x57e09abd in properties_changed_non_standard gdbus/client.c:544
    #8 0x57df2e00 in signal_filter gdbus/watch.c:394
    #9 0x57df4d57 in message_filter gdbus/watch.c:544
    #10 0x57752dc6 in dbus_connection_dispatch dbus/dbus/dbus-connection.c:4703
    #11 0x57dde7d5 in message_dispatch gdbus/mainloop.c:59
    #12 0x5790e3b8 in g_idle_dispatch glib/glib/gmain.c:6157
    #13 0x57900a31 in g_main_dispatch glib/glib/gmain.c:3477
    #14 0x579080d3 in g_main_context_dispatch glib/glib/gmain.c:4195
    #15 0x57908bcc in g_main_context_iterate glib/glib/gmain.c:4271
    #16 0x57909e7f in g_main_loop_run glib/glib/gmain.c:4471
    #17 0x57dde5b7 in telephonytool_main /home/djz/workspace/test/sim/frameworks/telephony/telephony_tool.c:878
    #18 0x56ea66b5 in nxtask_startup sched/task_startup.c:70
    #19 0x56e541a8 in nxtask_start task/task_start.c:134

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
wangbowen6 b854979073 system_properties: not use atomic operation to solve compile error
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:11 +08:00
openvela-robot 9a524577b0 system_properties: add android system property wrapper layer
There are still three fail test cases (android property test):
1. empty key test, reason: kvdb do not support empty key;
2. long key test, reason: (a) read only property value length can be
   arbitrarily-long in android, kvdb do not support; (b) read only
   property can be set if the property do not exist before, kvdb
   not allowed this action;
3. cached property test, reason: (a) android cached property uses
   serial to judge the [key, value] changed, kvdb can't handle this
   very well; (b) android cached property return the value pointer
   from the shared memory directly for read only property, kvdb
   can't handle this well too.

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 156f8c72bf frameworks/gdbus: replace glib api
1. using dbus-list api to replace glib list.
2. using dbus-hash api to replace glib hash api.
3. using dbus-string api to replace glib string api.
4. using posix memory api to replace glib memory api.
5. ...

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 380ee90b2d framework/gdbus: parse property base non-standard property method.
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 82a9c0b5f2 gdbus: remove glib header file from gdbus.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 8fbd2ec0c9 framework/gdbus: remove prefix g_ for gdbus api.
1. Remove prefix g_ for all gdbus api
2. Using macro to compatible g_ gdus api

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 67b57fbff7 utils/gdbus: fix compile warning
gdbus/client.c: In function ‘dbus_client_set_proxy_handlers’:
gdbus/client.c:1514:60: warning: declaration of ‘proxy_added’ shadows a global declaration [-Wshadow]
 1514 |                                         GDBusProxyFunction proxy_added,
      |                                         ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
gdbus/client.c:365:13: note: shadowed declaration is here
  365 | static void proxy_added(GDBusClient *client, GDBusProxy *proxy)
gdbus/object.c: In function ‘dbus_pending_error’:

gdbus/object.c:319:51: warning: declaration of ‘pending’ shadows a global declaration [-Wshadow]
  319 |                                 GDBusPendingReply pending,
      |                                 ~~~~~~~~~~~~~~~~~~^~~~~~~
gdbus/object.c:76:16: note: shadowed declaration is here
   76 | static GSList *pending = NULL;
      |                ^~~~~~~

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
dongjiuzhu1 1fc1c07c3d Revert "gdbus: fix compile break[workaround]"
This reverts commit d1ba28fc5cbc0e4518eced037ec3bf49768b33b0.
2025-12-15 18:24:11 +08:00
dongjiuzhu1 373a7a856f gdbus: fix compile break[workaround]
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:11 +08:00
Luiz Augusto von Dentz 969f21eca4 gdbus: Emit InterfacesAdded of parents objects first
This makes InterfacesAdded respect the object hierarchy in case its
parent has pending interfaces to be added.

Fixes: https://github.com/bluez/bluez/issues/272
Fixes: https://github.com/bluez/bluez/issues/284
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1534857
Fixes: https://bugs.archlinux.org/task/57464
2025-12-15 18:24:10 +08:00
Tedd Ho-Jeong An 47341f1878 gdbus: Add SPDX License Identifier
This patch adds SPDX License Identifier and removes the license text.

-------------------------------------
       License            COUNT
-------------------------------------
 GPL-2.0-or-later     :      6

License: GPL-2.0-or-later
   gdbus/mainloop.c
   gdbus/object.c
   gdbus/polkit.c
   gdbus/client.c
   gdbus/watch.c
   gdbus/gdbus.h
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz 3571298c49 gdbus: Make g_dbus_proxy_get_path take const proxy
This makes g_dbus_proxy_get_path take const proxy since it doesn't
change anything on the proxy and avoid pointless casts.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz f547545e8c gdbus: Split validation of object path and interface
This splits the validation of object and interface so and error is
properly printed for each of those.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz b121603315 gdbus: Make sure the object path and interface are valid
D-Bus object path and interface must be validate otherwise it can cause
errors as follow:

0  0xb7f67ab1 in __kernel_vsyscall ()
1  0xb7ca1cc1 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
2  0xb7ca50ee in abort () at abort.c:92
3  0xb7e30ba5 in _dbus_abort () at dbus-sysdeps.c:94
4  0xb7e267a6 in _dbus_warn_check_failed (
    format=0xb7e36cd4 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\nThis is normally a bug in some application using the D-Bus library.\n") at dbus-internals.c:290
5  0xb7e16d9f in dbus_message_iter_append_basic (iter=0xbf864400, type=111,
    value=0xd70940) at dbus-message.c:2586
6  0x004fcdec in emit_interfaces_added (user_data=0xd70938)
    at gdbus/object.c:574
2025-12-15 18:24:10 +08:00
Marcel Holtmann a991b6e0d9 build: Move declaration of _GNU_SOURCE back into individual source files 2025-12-15 18:24:10 +08:00
ERAMOTO Masaya a9b1f90a29 gdbus: Introduce functions appending to dbus message 2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz c82af41ced gdbus: Fail to send NULL messages
This should make it safe to call g_dbus_send_message with a NULL
message which is more likely to happen now that g_dbus_create_reply
returns NULL when the message is marked with NO_REPLY flag.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz b0f7382e65 gdbus: Fix replying to messages marked with NOREPLY flag
When a sender flags a D-Bus message as not expecting a reply, it is
against D-Bus policy to send a reply — sending one can result in an
error as reported in:

https://bugzilla.kernel.org/show_bug.cgi?id=198453
2025-12-15 18:24:10 +08:00
ERAMOTO Masaya 15551b602c client: Use g_dbus_proxy_path_lookup() 2025-12-15 18:24:10 +08:00
ERAMOTO Masaya 45ab428a01 gdbus: Introduce g_dbus_proxy_path_lookup()
g_dbus_proxy_path_lookup() returns the path of the proxy that matches the
passed path. It also returns the index of the proxy coming next to the
matched proxy in the passed list.
2025-12-15 18:24:10 +08:00
ERAMOTO Masaya 2b7bb6639b gdbus: Make proxy_lookup() global
Also adds the following feature to g_dbus_proxy_lookup().
 - It is more robust even if a proxy is NULL.
 - It checks if the passed interface is NULL.
 - It looks up from the position of the list specified by the index.
2025-12-15 18:24:10 +08:00
Szymon Janc 6b990db97c gdbus: Fix crash on proxy remove
If proxy was freed due to interface being removed remaining references
are left with NULL client pointer. We need to cancel pending calls that
require client when getting reply.

This fix following crash:
bluetoothd[2773]: src/gatt-database.c:proxy_removed_cb() Proxy removed - removing service: /test/app/hci0/service2
bluetoothd[2773]: src/gatt-database.c:gatt_db_service_removed() Local GATT service removed
bluetoothd[2773]: src/adapter.c:adapter_service_remove() /org/bluez/hci0
bluetoothd[2773]: src/adapter.c:remove_uuid() sending remove uuid command for index 0
bluetoothd[2773]: src/sdpd-service.c:remove_record_from_server() Removing record with handle 0x10008
bluetoothd[2773]: src/gatt-database.c:client_disconnect_cb() Client disconnected
==2773== Invalid read of size 8
==2773==    at 0x485220: proxy_added (client.c:288)
==2773==    by 0x485220: get_all_properties_reply (client.c:316)
==2773==    by 0x515A041: ??? (in /lib/x86_64-linux-gnu/libdbus-1.so.3.14.6)
==2773==    by 0x515DA60: dbus_connection_dispatch (in /lib/x86_64-linux-gnu/libdbus-1.so.3.14.6)
==2773==    by 0x47F2BF: message_dispatch (mainloop.c:72)
==2773==    by 0x4E84049: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==2773==    by 0x4E843EF: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==2773==    by 0x4E84711: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2)
==2773==    by 0x40B51F: main (main.c:770)
==2773==  Address 0x88 is not stack'd, malloc'd or (recently) free'd
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz ecff015e0b gdbus: Force service to start if proxy is created while not connected
Because GetAll is no longer send right away the service may never be
started.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz bbbf8a6575 gdbus: Fix not emiting PropertiesChanged
If and interface is removed while properties are pending it would cause
process_properties_from_interface to clear data->pending_prop when it
should only clear the iface->pending_prop.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz 1f6be796da gdbus: Fix not always appending proxy to the list
Changes introduced by c4df79642f413fd7cd7f7da39c3a1f2a184eccae have a
regression were a proxy may not be appended to the proxy_list causing
tests to fail as the proxies maybe be added multiple time since
proxy_look would not be able to find existing instances.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz f88a3186fb gdbus: Fix calling GetAll while GetManagedObjects is pending
If proxies are created while the client is not ready put them into a
pending list so only if they are not found in GetManagedObject reply
call GetAll.
2025-12-15 18:24:10 +08:00
Vinicius Costa Gomes 930a034820 gdbus: Fix the ordering of signals
Consider the following example:

/foo
  properties: "A", "B"

/bar
  properties: "C", "D"

If during a given mainloop iteration, property "A" of object '/foo' is
changed, then properties "C" and "D" of '/bar', lastly "B" of '/foo',
the current code will emit the PropertiesChanged signals in following
order: "A", "B", "C", "D".

This may confuse applications that have a dependency on the order of
those signals.

This fixes the ordering, so in the example, the order becomes:
"C", "D", "A", B". This is considered not to be a problem, as
applications may use the flag G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH, so
property changed signals are emitted as soon as possible.

The solution is for each object, to reschedule the signals every time a
signal is emitted.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz 360e1f3422 gdbus/client: Use g_dbus_send_message if callback is not set
If the user don't set a function it means it doesn't specific producte about the reply
so g_dbus_send_message can be used.
2025-12-15 18:24:10 +08:00
Luiz Augusto von Dentz 795f529669 gdbus/client: Always call ready callback
Call ready callback regardless of the reply to GetManagedObjects
since otherwise the user code will be left waiting forever when in fact
no proxy will be created.
2025-12-15 18:24:10 +08:00
Grant Erickson 1d2f134d77 gdbus: Move typedefs for interwork with strict compilers
Move enumeration type defintions AFTER the enumerations themselves are
declared and defined such that the header works with strict compilers.

This occurs when building a plugin, compiled with C++, and occurs on
all of:

arm-none-linux-gnueabi-g++ (Sourcery G++ Lite 2010q1-202) 4.4.1
arm-poky-linux-gnueabi-g++ (GCC) 4.8.2
g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
2025-12-15 18:24:10 +08:00
Saurav Babu 21e521aab5 gdbus: Fix Memory Leak
Members of data are allocated memory but not freed only data is freed
2025-12-15 18:24:10 +08:00
Philip Withnall 5123353f75 gdbus: Drop message replies if the sender requested no reply
If the sender flags a D-Bus message as not expecting a reply, it is
against system bus policy to send a reply — sending one will result in
errors being sent to us by dbus-daemon.

Magically drop all replies to messages which request no reply.

ofonod is one process which sends BlueZ messages which request no
reply,
when it is setting up a hands-free agent.

This is not a complete fix. In an ideal world, the existing check for
G_DBUS_METHOD_FLAG_NOREPLY would be dropped, as the server should be
prepared to return a reply to every method, if the client requests and
expects one — otherwise the client will time out. However, that’s a
much
bigger change with a much bigger risk of breaking things, so I’ll stick
with this for now.
2025-12-15 18:24:10 +08:00
Johan Hedberg f1f079a03a gdbus: Remove unnecessary empty line 2025-12-15 18:24:10 +08:00
Jakub Pawlowski f57229a71c gdbus: add method for immediate property update
g_dbus_emit_property_changed doesn't send dbus signal immediately. Instead
it stores changed properties, and schedule signal to be send at
g_iddle_add. Additionally, if this method is called few times for some
property, only last value will be sent in property changed signal.

If remote device sends lots of notifications, they're all scheduled to be
notified using this method. This might result in some notifications being
lost.

This patch adds new method, that can immediately send property changed
signal, instead of sheduling it for nearest iddle moment.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 81e370dca4 gdbus: Close private connection if setup fails
Private connection should be properly closed with dbus_connection_close
otherwise libdbus exits with the following error:

  'The last reference on a connection was dropped without closing the
   connection. This is a bug in an application. See
   dbus_connection_unref() documentation for details. Most likely, the
   application was supposed to call dbus_connection_close(), since this
   is a private connection.'
2025-12-15 18:24:09 +08:00
Szymon Janc 5415101d00 gdbus: Fix crash in g_dbus_create_error_valist
Passing NULL format parameter to vsnprintf results in invalid argument
error on glibc. But with some other libc libraries (musl and uClibc)
this results in dereferencing NULL pointer and crash due to
segmentation fault.
2025-12-15 18:24:09 +08:00
Szymon Janc 1bbde9ca87 gdbus: Use g_dbus_create_error_valist internally
There is no need to duplicate code in g_dbus_send_error_valist.
2025-12-15 18:24:09 +08:00
Michael Janssen 7b42da75e7 gdbus: Add g_dbus_get_flags function
The g_dbus_get_flags function enables detection of when the
G_DBUS_FLAG_ENABLE_EXPERIMENTAL is set.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 6e577247af gdbus: Make GDBusClient work without ObjectManager
This makes GDBusClient work normally without ObjectManager.
2025-12-15 18:24:09 +08:00
Arman Uguray eddfa1fc63 gdbus/client: Allow specifying ObjectManager path
GDBusClient currently hard-codes "/" as the remote ObjectManager path.
This is generally incorrect, as an application can choose to expose an
ObjectManager at any well-known path. This patch fixes this by allowing
the user to pass in the ObjectManager path by introducing a new
conctructor "g_dbus_client_new_full".
2025-12-15 18:24:09 +08:00
Arman Uguray bfcccef026 gdbus/client: Don't GetManagedObjects w/o handlers
The client code currently issues GetManagedObjects if new handlers are
set via g_dbus_client_set_proxy_handlers. An application may set these
to NULL before unref'ing a client or to simply prevent further events.
Hence, there is no need to refresh objects or properties if all handlers
are NULL.
2025-12-15 18:24:09 +08:00
Szymon Janc 5ae81a0eb9 gdbus: Fix not calling disconnect function
If daemon gets disconnected from D-Bus sender is NULL. Watches that
was explicitly added with NULL sender (ie disconnected_signal in
g_dbus_set_disconnect_function) should be called anyway.
2025-12-15 18:24:09 +08:00
Arman Uguray 08b1e87b31 gdbus: Don't refresh objects/props if disconnected
If g_dbus_client_set_proxy_handlers gets called from within a
proxy_removed callback, the code may end up refreshing the proxy's
properties and incorrectly access the client's proxy_list as it gets
freed. This patch fixes this, so that get_managed_objects does nothing
if it gets called during a service disconnect.
2025-12-15 18:24:09 +08:00
Alban Crequy 723467c703 gdbus: Fix match rule for NameOwnerChanged
When subscribing to the D-Bus signal NameOwnerChanged from the bus driver,
specify the object path and the sender in the match rule. Otherwise, random
connections on the bus could impersonate the bus driver.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 9cd358432a gdbus: Fix crash when watch is toggled or disconnected
This partially reverts 609873e315e705cff3a62ee904675da06d30f7a4 since it
still necessary to take a reference before calling dbus_watch_handle
since internally it can call watch_info_free as in the following trace:

 Invalid read of size 8
   at 0x121085: watch_func (mainloop.c:105)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
 Address 0x5bbcd90 is 16 bytes inside a block of size 24 free'd
   at 0x4A079AE: free (vg_replace_malloc.c:427)
   by 0x4C7837E: g_free (gmem.c:252)
   by 0x4F708BF: dbus_watch_set_data (dbus-watch.c:614)
   by 0x4F70938: _dbus_watch_unref (dbus-watch.c:132)
   by 0x4F6E9A7: _dbus_transport_handle_watch (dbus-transport.c:884)
   by 0x4F59AFB: _dbus_connection_handle_watch (dbus-connection.c:1497)
   by 0x4F70AF9: dbus_watch_handle (dbus-watch.c:683)
   by 0x121084: watch_func (mainloop.c:103)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz cdb3c9572a gdbus: Fix crash when calling g_dbus_add_service_watch
If g_dbus_add_service_watch is called for service which bus name is
already known the following crash can happen:

invalid read of size 1
  at 0x4C2A2F2: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  by 0x4E97722: g_strdup (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x405B0C: update_name_cache (watch.c:435)
  by 0x405C37: update_service (watch.c:593)
  by 0x4E7A2A5: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7AA39: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4038EA: client_ready (test-gdbus-client.c:1014)
  by 0x4E9E5E0: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9EB1A: g_test_run_suite (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x403614: main (test-gdbus-client.c:1058)
Address 0x5dbe5d0 is 0 bytes inside a block of size 7 free'd
  at 0x4C28577: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  by 0x4E7FF7E: g_free (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x405B04: update_name_cache (watch.c:434)
  by 0x405C37: update_service (watch.c:593)
  by 0x4E7A2A5: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7A627: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E7AA39: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4038EA: client_ready (test-gdbus-client.c:1014)
  by 0x4E9E5E0: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9E7A5: ??? (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x4E9EB1A: g_test_run_suite (in /usr/lib64/libglib-2.0.so.0.3800.2)
  by 0x403614: main (test-gdbus-client.c:1058)
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz edff96484c Revert "gdbus: Don't include just added interfaces in GetManagedObjects"
This actually creates a problem since the code now does flush any pending
message on the queue any signal will be send right away before the
actual reply to GetManagedObjects which will not contain those interfaces.
2025-12-15 18:24:09 +08:00
Andrei Emeltchenko b2c8718e45 gdbus: Fix use after free
Refactor filter_data_remove_callback so that we do not iterate over
freed pointer.
2025-12-15 18:24:09 +08:00
Claudio Takahasi 21a2544c9d gdbus: Avoid reporting GDBusClient disconnect twice
No matter if disconnection was reported previously, g_dbus_client_unref()
was always calling service disconnect callback. This patch fix the
following scenario:
1) service disconnects from the bus
2) disconnect callback gets called
3) client calls g_dbus_client_unref(), disconnect callback is called
   again.
2025-12-15 18:24:09 +08:00
Claudio Takahasi 337f1b31bb gdbus: Add g_dbus_proxy_set_property_array
This patch adds a new gdbus utility function to allow setting a property
of fixed, and non-fixed values array.
2025-12-15 18:24:09 +08:00
Claudio Takahasi 2df131ce0d gdbus: Add g_dbus_client_set_ready_watch()
This patch adds a new gdbus helper to notify the clients that
GetManagedObjects reply was received and the last proxy has been
informed previously by the proxy_added callback.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 686fc26441 gdbus: Replace g_timeout_add with g_idle_add
Passing 0 as timeout to g_timeout_add should equivalent to g_idle_add.
2025-12-15 18:24:09 +08:00
Anderson Lizardo 282235f941 gdbus: Fix incorrect DBusConnection reference counting
Commit 94d4f8c35f2e8f301aab7f55a6b7ea8d8c26305e attempted to fix a crash
related to improper reference counting, but the main issue was that the
reference was taken only during the function call (which is usually
unnecessary for single thread), but still passed a pointer to
DBusConnection to a function that is called by the mainloop. This left a
window where the DBusConnection can be destroyed.

Fixes this crash on unit/test-gdbus-client:

==32642== Invalid read of size 4
==32642==    at 0x690D0A6: dbus_connection_ref (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x804CEDB: message_dispatch (mainloop.c:73)
==32642==    by 0x684580E: g_timeout_dispatch (gmain.c:4450)
==32642==    by 0x6844A75: g_main_context_dispatch (gmain.c:3065)
==32642==    by 0x6844E14: g_main_context_iterate.isra.23 (gmain.c:3712)
==32642==    by 0x68452FA: g_main_loop_run (gmain.c:3906)
==32642==    by 0x804C7D3: client_connect_disconnect
(test-gdbus-client.c:188)
==32642==    by 0x6868DB2: g_test_run_suite_internal (gtestutils.c:2067)
==32642==    by 0x6868F8D: g_test_run_suite_internal (gtestutils.c:2138)
==32642==    by 0x6869320: g_test_run_suite (gtestutils.c:2189)
==32642==    by 0x686936B: g_test_run (gtestutils.c:1508)
==32642==    by 0x696D4D2: (below main) (libc-start.c:226)
==32642==  Address 0x709c6e4 is 140 bytes inside a block of size 144
free'd
==32642==    at 0x67E806C: free (in
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==32642==    by 0x692D62E: dbus_free (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x690E1C2: ??? (in
/lib/i386-linux-gnu/libdbus-1.so.3.7.6)
==32642==    by 0x804AAEC: destroy_context (test-gdbus-client.c:104)
==32642==    by 0x6868DB2: g_test_run_suite_internal (gtestutils.c:2067)
==32642==    by 0x6868F8D: g_test_run_suite_internal (gtestutils.c:2138)
==32642==    by 0x6869320: g_test_run_suite (gtestutils.c:2189)
==32642==    by 0x686936B: g_test_run (gtestutils.c:1508)
==32642==    by 0x696D4D2: (below main) (libc-start.c:226)
2025-12-15 18:24:09 +08:00
Anderson Lizardo 739ae6ef26 gdbus: Fix memory leak
data->conn and data->path must be destroyed before freeing "data".
2025-12-15 18:24:09 +08:00
Bastien Nocera 213fed6add gdbus: Fix trying to remove already removed sources
When we return FALSE from idle handlers, the source is removed.
This will be causing warnings in glib 2.40.

See https://bugzilla.gnome.org/show_bug.cgi?id=710724
2025-12-15 18:24:09 +08:00
Szymon Janc 0465d86991 gdbus: Remove not needed check for NULL DBusPendingCall
It is now checked by g_dbus_send_message_with_reply() so there is no
need to double check that in caller.
2025-12-15 18:24:09 +08:00
Szymon Janc 4c125d6ad5 gdbus: Check for NULL DBusPendingCall in g_dbus_send_message_with_reply
"Warning: if the connection is disconnected or you try to send Unix file
descriptors on a connection that does not support them, the
DBusPendingCall will be set to NULL, so be specific producteful with this."

Check this in g_dbus_send_message_with_reply so that callers don't need
to double check for NULL if g_dbus_send_message_with_reply returned
TRUE.

This also fix crash if passing FD over D-Bus is blocked e.g. by SELinux
policy.

bluetoothd[1894]: profiles/audio/avdtp.c:session_cb()
bluetoothd[1894]: profiles/audio/avdtp.c:avdtp_parse_cmd() Received
    SET_CONFIGURATION_CMD
bluetoothd[1894]: profiles/audio/a2dp.c:endpoint_setconf_ind() Source
    0x6c5000: Set_Configuration_Ind
bluetoothd[1894]: profiles/audio/avdtp.c:avdtp_ref() 0x6df360: ref=1
bluetoothd[1894]: profiles/audio/a2dp.c:setup_ref() 0x6d32b0: ref=1
process 1894: arguments to dbus_pending_call_set_notify() were incorrect,
     assertion "pending != NULL" failed in file dbus-pending-call.c line
     636.
This is normally a bug in some application using the D-Bus library.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 9463f0ab3c gdbus/client: Use g_dbus_add_properties_watch to track properties
This make the handling much simpler and avoids duplicates of the same
match rule.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz bc4c2efd74 gdbus/client: Use g_dbus_add_signal_watch to track signals
This make the handling much simpler and avoids duplicates of the same
match rule.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz b8862d34d3 gdbus/client: Use g_dbus_add_service_watch to track services
This make the handling much simpler and avoids duplicates of the same
match rule.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz d48d0a4b3e gdbus/watch: Fix crash when disconnecting from D-Bus
When disconnecting from D-Bus a message could be recieved with no sender:
Invalid read of size 1
   at 0x4A09EE1: strcmp (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x3B03C386B8: g_str_equal (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x4065D6: message_filter (watch.c:529)
   by 0x3B0700F9E5: dbus_connection_dispatch (in /usr/lib64/libdbus-1.so.3.7.4)
   by 0x4052E7: message_dispatch (mainloop.c:76)
   by 0x3B03C48962: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x3B03C47E05: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x3B03C48157: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x3B03C48559: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x4038C5: client_proxy_removed (test-gdbus-client.c:902)
   by 0x3B03C6B566: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
   by 0x3B03C6B6E5: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
 Address 0x0 is not stack'd, malloc'd or (recently) free'd
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz b9540df318 gdbus/watch: Fix aborting when removing D-Bus filter
In case of filter_data having a watch to a service name it may call
dbus_connection_remove_filter twice causing libdbus to abort:

process 24723: Attempt to remove filter function 0x4063e0 user data (nil), but no such filter has been added

To fix this the code will now only attempt to call
dbus_connection_remove_filter once in filter_data_free which is the
counterpart of filter_data_get where dbus_connection_add_filter is called.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 93e6a09726 gdbus/watch: Fix crash when g_dbus_remove_watch is called from connect callback
at 0x40570C: update_service (watch.c:601)
 by 0x40584B: service_reply (watch.c:627)
 by 0x3B0700C511: ??? (in /usr/lib64/libdbus-1.so.3.7.4)
 by 0x3B0700F740: dbus_connection_dispatch (in /usr/lib64/libdbus-1.so.3.7.4)
 by 0x405167: message_dispatch (mainloop.c:76)
 by 0x3B03C48962: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
 by 0x3B03C47E05: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.3600.3)
 by 0x3B03C48157: ??? (in /usr/lib64/libglib-2.0.so.0.3600.3)
 by 0x3B03C48559: g_main_loop_run (in /usr/lib64/libglib-2.0.so.0.3600.3)
Address 0x4c58a30 is 32 bytes inside a block of size 56 free'd
 at 0x4A074C4: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
 by 0x3B03C4D9AE: g_free (in /usr/lib64/libglib-2.0.so.0.3600.3)
 by 0x406102: filter_data_remove_callback (watch.c:378)
 by 0x405FC0: g_dbus_remove_watch (watch.c:798)
 by 0x40A22B: g_dbus_client_unref (client.c:1227)
 by 0x40570B: update_service (watch.c:599)
 by 0x40584B: service_reply (watch.c:627)
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 0c5a311077 gdbus: Fix emitting PropertiesChanged twice
This fixes double emission of PropertiesChanged introduced by flushing
changes, the flushing can happen during the pending processing so the
pending_prop flag needs to be updated in the beginning and the list of
properties can be freed before g_dbus_send_message as it is not required
anymore.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz e54a8ccf7b gdbus: Avoid calling dbus_connection_send*
dbus_connection_send* should not be called directly except by
g_dbus_send_message.
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 5f07e053e8 gdbus: Add g_dbus_send_message_with_reply
g_dbus_send_message_with_reply flushes pending signals before calling
dbus_connection_send_with_reply so it does not alter the message order
2025-12-15 18:24:09 +08:00
Luiz Augusto von Dentz 190b579c01 gdbus: Fix sending ObjectManager/Properties signals out of order
In some cases the order of the messages is altered when a message is
sent without processing the pending signals first, currently this affect
client_check_order unit test:

/gdbus/client_check_order: **
ERROR:unit/test-gdbus-client.c:795:property_check_order: assertion failed: (g_strcmp0(string, "value1") == 0)

As can be observed the value of the property is not yet updated because the
signal it is still pending, once this fix is applied the test pass:

/gdbus/client_check_order: OK

Note that the flushing only works when g_dbus_send_message is used so
places where dbus_connection_send and other variants are called directly
may still change the order.
2025-12-15 18:24:09 +08:00
Henrique Dante de Almeida 05bd22dfb6 gdbus: Remove proxies when client disconnects
Remove proxies and generate proxy_removed callbacks even when there are
no corresponding InterfaceRemoved signals.

This patch fixes having zombie gdbus proxy object when a server
disconnects without sending InterfaceRemoved signals. These objects
may interact with new server instances, for example, making
InterfaceAdded signals of new objects with the same name be filtered
out as duplicated, or staying allocated, but unused, if the new server
doesn't reuse the object paths. Note that as a side-effect, the
lifetime of a gdbus proxy becomes stricter: it lives at most for the
duration of a single connection to a single instance of a server
process.
2025-12-15 18:24:08 +08:00
Anderson Lizardo 307e4132eb gdbus: Fix using NULL DBusPendingCall when disconnected from D-Bus
From D-Bus documentation for dbus_connection_send_with_reply():

"Warning: if the connection is disconnected or you try to send Unix file
descriptors on a connection that does not support them, the
DBusPendingCall will be set to NULL, so be specific producteful with this."

Fix these errors when killing D-Bus daemon with the client still
running:

process 5712: arguments to dbus_pending_call_set_notify() were
incorrect, assertion "pending != NULL" failed in file
../../dbus/dbus-pending-call.c line 596.
This is normally a bug in some application using the D-Bus library.
process 5712: arguments to dbus_pending_call_unref() were incorrect,
assertion "pending != NULL" failed in file
../../dbus/dbus-pending-call.c line 572.
This is normally a bug in some application using the D-Bus library.
2025-12-15 18:24:08 +08:00
Anderson Lizardo f2b00d18b6 gdbus: Fix segfault when D-Bus daemon exits
Fix this crash if D-Bus exits while the client is still connected to it:

==5570== Invalid read of size 1
==5570==    at 0x402D28E: strcmp (in
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5570==    by 0x4070E22: g_str_equal (ghash.c:1704)
==5570==    by 0x8055F61: message_filter (client.c:1123)
==5570==    by 0x4141500: dbus_connection_dispatch (in
/lib/i386-linux-gnu/libdbus-1.so.3.5.8)
==5570==    by 0x80506F7: message_dispatch (mainloop.c:76)
==5570==    by 0x4081A7E: g_timeout_dispatch (gmain.c:3882)
==5570==    by 0x4080D85: g_main_context_dispatch (gmain.c:2539)
==5570==    by 0x4081124: g_main_context_iterate.isra.21 (gmain.c:3146)
==5570==    by 0x408156A: g_main_loop_run (gmain.c:3340)
==5570==    by 0x41BF4D2: (below main) (libc-start.c:226)
==5570==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==5570==
==5570==
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz cabe78d7a6 gdbus: Fix calling GetManagedObjects twice in a row
Calling g_dbus_client_new followed by g_dbus_client_set_proxy_handlers
cause two calls to GetManagedObjects in a row as GetNameOwner reply is
asyncronously it triggers the second call because the handlers have
been set by g_dbus_client_set_proxy_handlers.
2025-12-15 18:24:08 +08:00
Lucas De Marchi d57b1979d5 gdbus: Use gcc builtin instead of g_atomic
g_atomic_* end up using G_STATIC_ASSERT, causing gcc 4.8 to yell due to
-Wunused-local-typedefs.

gdbus/client.c: In function ‘g_dbus_client_ref’:
/usr/include/glib-2.0/glib/gmacros.h:162:53: error: typedef ‘_GStaticAssertCompileTimeAssertion_2’ locally defined but not used [-Werror=unused-local-typedefs]
 #define G_STATIC_ASSERT(expr) typedef char G_PASTE (_GStaticAssertCompileTimeAssertion_, __COUNTER__)[(expr) ? 1 : -1]
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz 3564bc897f gdbus: Fix not calling property_changed callback
In case a property did not appear by the time proxy_added was called
property_changed has to be called if it appear latter otherwise the
application will be unaware of it.
2025-12-15 18:24:08 +08:00
Tomasz Bursztyka 640c13a7da gdbus: Always unreference the message in g_dbus_send_message()
A quick fix on g_dbus_send_message(), if check_signal() fails it returns
FALSE without unreferencing the message as it should. This patch fixes
it.
2025-12-15 18:24:08 +08:00
Denis Kenzior ea704f767b gdbus: Add g_dbus_proxy_set_removed_watch 2025-12-15 18:24:08 +08:00
Vinicius Costa Gomes 9f71038908 gdbus: Fix missing PropertiesChanged signal
If D-Bus ObjectManager is not supported, InterfacesAdded signal
checking needs to be ignored otherwise PropertiesChanged signal
will never be sent.
2025-12-15 18:24:08 +08:00
Marcel Holtmann 24a199849e gdbus: Don't call property changed callback during client init
When the client uses ObjectManager to init properties, do not call
property changed callbacks. They should only be called once the proxy
added has been successfully signaled since the proxy itself provides
a full copy of available properties.
2025-12-15 18:24:08 +08:00
Johan Hedberg f0cc3f1a51 gdbus: Fix unpublished interface signal emission
If we haven't published an interface yet (i.e. it's in the data->added
list), we should just ignore any property changed indications as the
values for the properties will anyway be part of the InterfacesAdded
signal.
2025-12-15 18:24:08 +08:00
Marcel Holtmann f6328ee282 gdbus: Check for valid path before handling properties 2025-12-15 18:24:08 +08:00
Anderson Lizardo 5533e47eef gdbus: Fix memory leak on properties_set()
The pointer returned by dbus_message_iter_get_signature() must be freed
with dbus_free().

Fixes this memory leak:

==1857== 16 bytes in 1 blocks are definitely lost in loss record 104 of
251
==1857==    at 0x402BF52: realloc (in
/usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1857==    by 0x415E286: dbus_realloc (in
/lib/i386-linux-gnu/libdbus-1.so.3.5.8)
==1857==    by 0x415E70B: ??? (in
/lib/i386-linux-gnu/libdbus-1.so.3.5.8)
==1857==    by 0x415F17B: ??? (in
/lib/i386-linux-gnu/libdbus-1.so.3.5.8)
==1857==    by 0x414CB33: dbus_message_iter_get_signature (in
/lib/i386-linux-gnu/libdbus-1.so.3.5.8)
==1857==    by 0x8053239: properties_set (object.c:899)
==1857==    by 0x5FFFFF: ???
==1857==
2025-12-15 18:24:08 +08:00
Marcel Holtmann 1e875eee5c gdbus: Check signature of property value before calling setter 2025-12-15 18:24:08 +08:00
Lucas De Marchi 0d9a354d5e gdbus: Don't include just added interfaces in GetManagedObjects
If we received a call to ObjectManager.GetManagedObject we should not
include in the response the interfaces in data->added. This is because
it's not guaranteed that those interfaces will trigger an
InterfacesAdded signal, which is the case if the interface is removed in
the same mainloop iteration.
2025-12-15 18:24:08 +08:00
Lucas De Marchi 344b724082 gdbus: Simplify generated introspection
The generated introspection is not supposed to be read as is by human,
so there's no point in printing the indentation or writing more code to
use auto-close tags.

If it's desired to read the raw xml file, user can always use other
tools to transform the output such as "xmllint --format".

This also fixes a missing </property> when property is deprecated.
2025-12-15 18:24:08 +08:00
Marcel Holtmann 8585f8dafc gdbus: Hold client reference during get name owner reply 2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz 50a8e5b3e3 gdbus: Call check_signals when sending signals with g_dbus_send_message
If message passed to g_dbus_send_message is a signal verify if it is a
valid and there really exists an interface with respective signal name.
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz b8757ac11d gdbus: Check if the interface being registered is valid
This prevent registering interfaces that are empty or have all members
marked as experiemental.
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz b02c416e7e gdbus: Introduce G_DBUS_PROPERTY_FLAG_EXPERIMENTAL
This flag can be used to mark properties as experimental, marked
properties are disabled by default and can be enabled by setting
G_DBUS_FLAG_ENABLE_EXPERIMENTAL using g_dbus_set_flags.
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz f0655f8b0f gdbus: Introduce G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
This flag can be used to mark signals as experimental, marked
signals are disabled by default and can be enabled by setting
G_DBUS_FLAG_ENABLE_EXPERIMENTAL using g_dbus_set_flags.
2025-12-15 18:24:08 +08:00
Luiz Augusto von Dentz efcaeb68c0 gdbus: Introduce G_DBUS_METHOD_FLAG_EXPERIMENTAL
This flag can be used to mark methods as experimental, marked
methods are disable by default and can be enabled by setting
G_DBUS_FLAG_ENABLE_EXPERIMENTAL using g_dbus_set_flags.
2025-12-15 18:24:08 +08:00
Marcel Holtmann 251c7c08b5 gdbus: Include changed properties only once per signal 2025-12-15 18:24:08 +08:00
Marcel Holtmann 0697bc24e9 gdbus: Update properties on D-Bus client re-connections 2025-12-15 18:24:08 +08:00
Marcel Holtmann 9a0702bccb gdbus: Add function to manually refresh properties 2025-12-15 18:24:08 +08:00
Marcel Holtmann e9317d35ea gdbus: Add support for proxy property change notifications 2025-12-15 18:24:08 +08:00
Marcel Holtmann 7564954162 gdbus: Fix handling of client connect/disconnect signals 2025-12-15 18:24:08 +08:00
Marcel Holtmann 9303ef8a16 gdbus: Protect standalone proxy creation with client reference 2025-12-15 18:24:08 +08:00
Marcel Holtmann 41f8504c6c gdbus: Use object manager only if callback functions are set 2025-12-15 18:24:08 +08:00
Marcel Holtmann 727c8ef15d gdbus: Use client service name and not hardcoded org.bluez 2025-12-15 18:24:08 +08:00
Marcel Holtmann d79816cdf0 gdbus: Add support for creating D-Bus proxies without object manager 2025-12-15 18:24:08 +08:00
Marcel Holtmann 0cfd7e7442 gdbus: Avoid using g_ptr_array_new_full convenience function
The g_ptr_array_new_full function only got introduced with GLib 2.30
and to avoid requiring a newer GLib use g_ptr_array_set_free_func instead.
2025-12-15 18:24:08 +08:00
Marcel Holtmann b698b288cf gdbus: Increase the method call timeout to 5 minutes 2025-12-15 18:24:08 +08:00
Marcel Holtmann 08bc2fca82 gdbus: Add helper for sending async error replies 2025-12-15 18:24:07 +08:00
Marcel Holtmann e1fc5e77f5 gdbus: Fix race condition with creating duplicate client proxies 2025-12-15 18:24:07 +08:00
Marcel Holtmann f95e6a90e8 gdbus: Fix issue with unref of client while parsing interfaces 2025-12-15 18:24:07 +08:00
Marcel Holtmann 045f081101 gdbus: Fix issue with unref of client in connect handler 2025-12-15 18:24:07 +08:00
Marcel Holtmann 7129b56fbc gdbus: Add support for D-Bus client method calls 2025-12-15 18:24:07 +08:00
Marcel Holtmann abe73a67dc gdbus: Add callback support for handling property changes 2025-12-15 18:24:07 +08:00
Marcel Holtmann d599968b1e gdbus: Handle property changed signals and update property 2025-12-15 18:24:07 +08:00
Marcel Holtmann 014b4b8d15 gdbus: Set property changed filter match rule for each proxy 2025-12-15 18:24:07 +08:00
Marcel Holtmann d61a3d45d1 gdbus: Use a GPtrArray for the match rules 2025-12-15 18:24:07 +08:00
Marcel Holtmann da5bc70d74 gdbus: Add support for setting D-Bus client basic properties 2025-12-15 18:24:07 +08:00
Marcel Holtmann c3226b8206 gdbus: Deep copy of variants also requires a signature 2025-12-15 18:24:07 +08:00
Marcel Holtmann 5a5c810bc9 gdbus: Add support for complex D-Bus client properties 2025-12-15 18:24:07 +08:00
Marcel Holtmann 6409610b7e gdbus: Add support for D-Bus client properties 2025-12-15 18:24:07 +08:00
Marcel Holtmann 1efcc10131 gdbus: Add support for D-Bus client proxies 2025-12-15 18:24:07 +08:00
Marcel Holtmann 4af3a499b6 gdbus: Add helper functions for simple D-Bus clients 2025-12-15 18:24:07 +08:00
Johan Hedberg 37869d91db Revert "Ensure config.h is included by using CPPFLAGS"
This reverts commit 76919ad7f431167cecdd3d608c1465961aa75423.

The patch needs to be split up and the gdbus/ changes were bogus
compared to the original commit message.

Conflicts:
	Makefile.am
	Makefile.obexd
	profiles/cyclingspeed/cyclingspeed.c
	profiles/heartrate/heartrate.c
	src/error.c
2025-12-15 18:24:07 +08:00
Lucas De Marchi 3ec486e4bf Ensure config.h is included by using CPPFLAGS
Instead of trying to include config.h in each file over the tree and
possibly forgetting to include it, give a "-include config.h" argument
to the compiler so it's guaranteed that a) it will be included for all
source files and b) it will be the first header included.

gdbus/ directory is left out, since it would break other projects using
it.
2025-12-15 18:24:07 +08:00
Luiz Augusto von Dentz 1e8bff6d19 gdbus: Add g_dbus_add_properties_watch function
Convenient function to create watches for D-Bus properties.
2025-12-15 18:24:07 +08:00
Lucas De Marchi d7bcab298b gdbus: Don't automatically attach ObjectManager
Let each project attach the object manager interface instead of
registering it automatically.
2025-12-15 18:24:07 +08:00
Lucas De Marchi e8c3ce5bc8 gdbus: Don't register DBus.Properties with no properties
Delay registering DBus.Properties interface until the moment there are
properties on that path. This is needed for objects that currently don't
expose any property to not export the interface.
2025-12-15 18:24:07 +08:00
Szymon Janc 47c7738b3f gdbus: Remove not needed NULL pointer checks
g_strdup returns NULL if argument passed is NULL and there is no need
to double check that.
2025-12-15 18:24:07 +08:00
Syam Sidhardhan e254b4b208 gdbus: Replace leading spaces with tabs
Trivial formatting fix.
2025-12-15 18:24:07 +08:00
Syam Sidhardhan d5b39ecf8c gdbus: Fix compilation error due to missing #defines
Since these are simple #define strings, we are defining it here
instead of upgrading to D-Bus 1.5 or later.

Log:
  CC     gdbus/object.o
gdbus/object.c: In function ‘properties_set’:
gdbus/object.c:876:7: error: ‘DBUS_ERROR_UNKNOWN_PROPERTY’ undeclared
 (first use in this function)
gdbus/object.c:876:7: note: each undeclared identifier is reported
 only once for each function it appears in
gdbus/object.c:881:6: error: ‘DBUS_ERROR_PROPERTY_READ_ONLY’
 undeclared (first use in this function)
make[1]: *** [gdbus/object.o] Error 1
make: *** [all] Error 2
2025-12-15 18:24:07 +08:00
Lucas De Marchi c32337cef6 gdbus: Remove connection from pending_property functions
The reply to a DBus.Properties.Set() method call should go through the
same D-Bus connection. Thus remove the DBusConnection parameter from the
following functions:

    - g_dbus_pending_property_success()
    - g_dbus_pending_property_error_valist()
    - g_dbus_pending_property_error()
2025-12-15 18:24:07 +08:00
Johan Hedberg 6d6169eb12 gdbus: Fix invalid memory access during interface removal
If an interface is removed from the root path during the same mainloop
iteration that it was added we need to check for data->added before
doing the check for data->parent == NULL in the remove_interface()
function. Otherwise the added interface doesn't get removed from the
data->added list and will result in accessing freed memory:

==337== Invalid read of size 8
==337==    at 0x4F65AFA: dbus_message_iter_append_basic (in /usr/lib64/libdbus-1.so.3.7.1)
==337==    by 0x1247B5: append_interface (object.c:556)
==337==    by 0x4C8DC5C: g_slist_foreach (gslist.c:840)
==337==    by 0x1261F7: process_changes (object.c:594)
==337==    by 0x126372: generic_unregister (object.c:997)
==337==    by 0x4F69669: ??? (in /usr/lib64/libdbus-1.so.3.7.1)
==337==    by 0x4F5CE51: dbus_connection_unregister_object_path (in /usr/lib64/libdbus-1.so.3.7.1)
==337==    by 0x125E81: object_path_unref (object.c:1236)
==337==    by 0x126136: g_dbus_unregister_interface (object.c:1361)
==337==    by 0x14CDF0: service_exit (service.c:581)
==337==    by 0x177556: plugin_cleanup (plugin.c:242)
==337==    by 0x12221F: main (main.c:559)
==337==  Address 0x5bc1550 is 0 bytes inside a block of size 56 free'd
==337==    at 0x4A079AE: free (vg_replace_malloc.c:427)
==337==    by 0x4C7850E: g_free (gmem.c:252)
==337==    by 0x125DB0: remove_interface (object.c:671)
==337==    by 0x125E3B: object_path_unref (object.c:1230)
==337==    by 0x126136: g_dbus_unregister_interface (object.c:1361)
==337==    by 0x14CDF0: service_exit (service.c:581)
==337==    by 0x177556: plugin_cleanup (plugin.c:242)
==337==    by 0x12221F: main (main.c:559)
2025-12-15 18:24:07 +08:00
Johan Hedberg f8d73e3b7d gdbus: Add g_dbus_get_properties function
This function can be used to construct custom D-Bus messages containing
the properties for a specific interface on a given path.
2025-12-15 18:24:07 +08:00
Johan Hedberg 73c593eed7 gdbus: Add support for invalidated properties
If there's a pending property but its exists() callback returns false
the property should be considered invalidated and included in the
relevant list of the PropertiesChanged signal.
2025-12-15 18:24:07 +08:00
Johan Hedberg 463be0e5b2 gdbus: Fix processing pending properties in remove_interface() 2025-12-15 18:24:07 +08:00
Lucas De Marchi 36bcc4b2d2 gdbus: Fix up Properties.Set() code path
Minor fixes to make setter actually work:

	- Add propdata in pending_property_set
	- Break loop when we are removing propdata from list and we
	  found it
	- in_args and out_args were swapped
	- interface and method name arguments were swapped
2025-12-15 18:24:07 +08:00
Lucas De Marchi 7ce811eef0 gdbus: Fix invalid memory access while unregistering
If an interface is added and removed on the same mailoop iteration,
ObjectManager would try to send InterfacesAdded signal while running the
idler because the interface was added to data->added list.

This is easily reproduced by forcing an error path in a plugin
registration, like on sap_server_register(), resulting in the following
error:

==11795== Invalid read of size 4
==11795==    at 0x496F592: dbus_message_iter_append_basic (dbus-message.c:2598)
==11795==    by 0x117B39: append_interface (object.c:554)
==11795==    by 0x48955E7: g_slist_foreach (gslist.c:840)
==11795==    by 0x11923B: process_changes (object.c:592)
==11795==    by 0x11956D: generic_unregister (object.c:980)
==11795==    by 0x4973BAC: _dbus_object_tree_unregister_and_unlock (dbus-object-tree.c:516)
==11795==    by 0x4965240: dbus_connection_unregister_object_path (dbus-connection.c:5776)
==11795==    by 0x1178A5: object_path_unref (object.c:1219)
==11795==    by 0x118517: g_dbus_unregister_interface (object.c:1344)
==11795==    by 0x19AF5B: sap_exit (sap.c:385)
==11795==    by 0x13E9E2: sap_server_register (server.c:1428)
==11795==    by 0x13C092: sap_server_probe (manager.c:44)

With this patch we don't send the InterfacesAdded signal, removing it
from data->added while unregistering.
2025-12-15 18:24:07 +08:00
Lucas De Marchi 975a24a1ff gdbus: Implement PropertiesChanged signal 2025-12-15 18:24:07 +08:00
Luiz Augusto von Dentz 960d2d27e9 gdbus: Simplify code for appending properties
This reuse append_properties for GetAll and GetManagedObjects
2025-12-15 18:24:07 +08:00
Luiz Augusto von Dentz 1bac6977af gdbus: Integrates ObjectManager with Properties interface
This appends the properties and its values when using ObjectManager.
2025-12-15 18:24:07 +08:00
Luiz Augusto von Dentz 47c19efa16 gdbus: Only export ObjectManager interface on root path
ObjectManager should be exported only in the root path and list all
the children paths.
2025-12-15 18:24:06 +08:00
Luiz Augusto von Dentz 5725e97799 gdbus: Group interface changes to reduce the amount of signals emitted
InterfacesAdded and InterfacesRemoved can group all the interfaces
changes together in one message.
2025-12-15 18:24:06 +08:00
Luiz Augusto von Dentz 7f639bef49 gdbus: Add support for org.freedesktop.DBus.ObjectManager interface
This implements initial support for ObjectManager, it automatically adds
objects to its parents so no action is needed by daemons to get their
objects managed by this interface.

ObjectManager is part of D-Bus spec since revision 0.17:
http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
2025-12-15 18:24:06 +08:00
Lucas De Marchi 94e8a5c67d gdbus: Add properties into Introspectable interface 2025-12-15 18:24:06 +08:00
Lucas De Marchi 5dfbb88b9c gdbus: Implement DBus.Properties.Set method
Contrary to Get() and GetAll(), Set() is asynchronous so we pass an id
to the setter so later it can declare the Set() as successful or
otherwise.
2025-12-15 18:24:06 +08:00
Lucas De Marchi c28afe1653 gdbus: Implement DBus.Properties.GetAll method 2025-12-15 18:24:06 +08:00
Lucas De Marchi 4f094c0501 gdbus: Implement DBus.Properties.Get method 2025-12-15 18:24:06 +08:00
Lucas De Marchi 31d6d4f894 gdbus: Add skeleton of DBus.Properties interface
This interface is responsible for handling properties of all objects in
a given path. Right now it only registers itself, doing nothing useful.
A conversion to this new layout will be done by subsequent patches.

org.freedesktop.org.DBus.Properties spec can be found at
http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
2025-12-15 18:24:06 +08:00
Lucas De Marchi 5ac1a6b233 gdbus: Use macros to add annotations
Besides being more readable this way it avoids going over 80 chars.
2025-12-15 18:24:06 +08:00
Lucas De Marchi a7c96b96c2 gdbus: Move typedefs up
Move the typedefs up so they can be used by functions and callbacks.
2025-12-15 18:24:06 +08:00
Luiz Augusto von Dentz 0a70554054 gdbus: Fix not freeing list node by using g_slist_delete_link
g_slist_remove_link does not free the node which can cause leaks so
replace that with g_slist_delete_link which does free memory properly.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 00c7da7fc9 gdbus: Refactor filter_data_find()
Now this function is only used for searching the listeners of a
connection and the other parameters are not needed anymore.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 4ae1ce7ded gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:

watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
						cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
						cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
						cb3, data3, NULL);

The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.

Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.

watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
						cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
						cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
						cb3, data3, NULL);

This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2025-12-15 18:24:06 +08:00
Johan Hedberg aea656b090 gdbus: Fix crash when getting disconnected from the bus
When getting disconnected from the bus sometimes (maybe always?)
dbus_watch_handle() can cause the "info" context to be free'd meaning
that we should not try to access it after the call. The only member we
need access to is the connection pointer and as the code already has a
ref() call for it it's only natural to solve the issue by adding a local
variable not dependent on "info".

The backtrace of the crash fixed looks as follows:

 Invalid read of size 8
   at 0x121085: watch_func (mainloop.c:105)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
 Address 0x5bbcd90 is 16 bytes inside a block of size 24 free'd
   at 0x4A079AE: free (vg_replace_malloc.c:427)
   by 0x4C7837E: g_free (gmem.c:252)
   by 0x4F708BF: dbus_watch_set_data (dbus-watch.c:614)
   by 0x4F70938: _dbus_watch_unref (dbus-watch.c:132)
   by 0x4F6E9A7: _dbus_transport_handle_watch (dbus-transport.c:884)
   by 0x4F59AFB: _dbus_connection_handle_watch (dbus-connection.c:1497)
   by 0x4F70AF9: dbus_watch_handle (dbus-watch.c:683)
   by 0x121084: watch_func (mainloop.c:103)
   by 0x4C72694: g_main_context_dispatch (gmain.c:2539)
   by 0x4C729C7: g_main_context_iterate.isra.23 (gmain.c:3146)
   by 0x4C72DC1: g_main_loop_run (gmain.c:3340)
   by 0x120541: main (main.c:551)
2025-12-15 18:24:06 +08:00
Jaganath Kanakkassery 3ddfc598f9 gdbus: Fix compilation error if macro "error" is defined
The variable "signature" used in error is not defined and "args" is now
a struct instead of a string.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 51203d47e4 gdbus: Fix removal of filter after last filter_data
If there's a signal watch that's also watching for name
(data->name_watch) currently we are trying to remove the message_filter
twice since we may have the following call chain:

filter_data_remove_callback()
  filter_data_free()
    g_dbus_remove_watch()
      filter_data_remove_callback()
	filter_data_free()
        dbus_connection_remove_filter()
  dbus_connection_remove_filter()

Because of this we can't currently watch for signals passing the bus
name. After this patch we don't have this issue anymore.

We fix it by removing the filter before calling filter_data_free() if we
are the last filter_data and thus avoid calling
dbus_connection_remove_filter() twice.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 4b10a2cfe5 gdbus: add macro for methods marked as NOREPLY 2025-12-15 18:24:06 +08:00
Mikel Astiz 71f621a95c gdbus: Fix incorrectly disspecific productded signals
Signals with no arguments were incorrectly filtered out due to the NULL
inequality check.
2025-12-15 18:24:06 +08:00
Lucas De Marchi a7c003c6b7 gdbus: do not check signature twice
Message signature is already checked in generic_message(), so there's no
need to check again in the callback.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 208aefa1ef gdbus: add Method.NoReply annotation in introspection 2025-12-15 18:24:06 +08:00
Lucas De Marchi e29fc301fd gdbus: add Deprecated annotation in introspection 2025-12-15 18:24:06 +08:00
Lucas De Marchi ae55d45e07 gdbus: remove signature and reply from tables 2025-12-15 18:24:06 +08:00
Lucas De Marchi 84b932d339 gdbus: loop over args to check message signature 2025-12-15 18:24:06 +08:00
Lucas De Marchi 9030b519c2 gdbus: use GDBusArgInfo to generate introspection
By using GDBusArgInfo in methods and signals, the introspection
generation is much simpler and we can add each argument name.
2025-12-15 18:24:06 +08:00
Lucas De Marchi 395189ff75 gdbus: add and use helpers for table declarations 2025-12-15 18:24:06 +08:00
Lucas De Marchi beeef8d9cb gdbus: add argument info to methods and signals 2025-12-15 18:24:06 +08:00
Marcel Holtmann 157de75d42 gdbus: Constify introspection method table 2025-12-15 18:24:06 +08:00
Lucas De Marchi 62ebc7d37c gdbus: do not call memset for terminating NUL 2025-12-15 18:24:06 +08:00
Lucas De Marchi 0f0a0dce2d gdbus: return if method signature is malformed 2025-12-15 18:24:06 +08:00
Marcel Holtmann 9e099e075e gdbus: Remove unneeded NEED_DBUS_WATCH_GET_UNIX_FD check 2025-12-15 18:24:06 +08:00
Anderson Lizardo eef1408e83 gdbus: Use destroy callback for service watch
Even though service watches accepted a "destroy" callback, they were
being ignored. This fix properly pass them along so they are called when
the watch is removed.
2025-12-15 18:24:06 +08:00
Syam Sidhardhan 1b68bd5d37 gdbus: Fix white space coding style issue
- corrected the space before '{'
2025-12-15 18:24:06 +08:00
Szymon Janc 9bd8b008c6 Remove unused result variable from g_dbus_pending_success 2025-12-15 18:24:06 +08:00
Grant Erickson b5ceca251a gdbus: Unconditionally remove D-Bus timeouts
Address an issue in which the daemon incorrectly handles D-Bus main
loop timeouts by only removing timeouts that are not enabled when
D-Bus requests a timeout removal.
2025-12-15 18:24:06 +08:00
Daniel Wagner 67de7dd271 gdbus: Remove root node 'name' attribute in introspection
generate_introspection_xml generates the root <node> tags with a
'name' attribute. This seems to be a valid attribute but it is not
consistent with the way the D-Bus daemon generates empty nodes.

For example if we register "/foo/bar", D-Bus daemon will generate for
"/foo" a introspection which looks like this:

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
  <node name="bar"/>
</node>

and generate_introspection_xml generates for "/foo/bar":

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/foo/bar">
</node>

Just don't add the 'name' attribute to the root node.  The GLib
binding for D-Bus does it the same way.
2025-12-15 18:24:06 +08:00
Daniel Wagner 5c72b8193c gdbus: invaldate_parent_data: walk the whole path down
Assume there is only one object registerd at "/". If we add a new
object at "/foo/bar" the introspection of "/" has to be updated. A new
node has to be added at "/".

invalidate_parent_data stops invaldating the whole path because the
boolean return value of dbus_connection_get_object_path_data is used
wrong.

If we get a TRUE just go on down in the path, if FALSE is return
dbus_connection_get_object_path_data has run out of memory.
2025-12-15 18:24:06 +08:00
Marcel Holtmann e9707aca9f gdbus: Update copyright information 2025-12-15 18:24:05 +08:00
Johan Hedberg 919e7b744b gdbus: fix accessing freed callback data
cb->disc_func or cb->conn_func could remove the callback so this needs
to be checked for before continuing processing.
2025-12-15 18:24:05 +08:00
Lucas De Marchi 5d9ea53b75 gdbus: explicitly compare pointers to NULL
This patch was generated by the following semantic patch
(http://coccinelle.lip6.fr/)

// <smpl>
@fix disable is_null,isnt_null1@
expression *E;
@@

- !E
+ E == NULL
// </smpl>
2025-12-15 18:24:05 +08:00
Luiz Augusto von Dentz 1b87eea590 gdbus: fix not handling bus disconnects
We where not dispatching data when a bus disconnects which cause
Disconnected signal to not be processed and thus causing the process to
either not exit or to not trigger callbacks registered with
g_dbus_set_disconnect_function.

To fix this now we always schedule a dispatch which will make sure data
still not processed will make its way to the proper handlers even if
disconnected.
2025-12-15 18:24:05 +08:00
Marcel Holtmann 0a73d922c9 Add support for builtin GDBus security using PolicyKit 2025-12-15 18:24:05 +08:00
Marcel Holtmann f77d9dfee6 Add support for GDBus security action and flags 2025-12-15 18:24:05 +08:00
Marcel Holtmann 242b93d85c Use simpler error callbacks for GDBus security hooks 2025-12-15 18:24:05 +08:00
Marcel Holtmann 57ddacceef Add support for GDBus security handlers 2025-12-15 18:24:05 +08:00
Luiz Augusto von Dentz f96b27a7e5 Fix calling watch callbacks after it has been removed
Pending call should be removed if the watch is removed since the
application no longer expect that to be reached and may already freed the
data associated with it.
2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz fba30b4954 Fix signal watch when a service name is given
The bus name should be resolved when adding a watch by service name since
messages do always come with sender set to owner's bus name, also it
should listen to owner updates since it can change without invalidating
the watch.
2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz 84bde444d7 Do not automatically remove watches for service names
Services can be owned again so it is perfectly fine to keep the watch.
2025-12-15 18:24:05 +08:00
Marcel Holtmann 4a60e27e0f Add printf format attribute for error creation helper 2025-12-15 18:24:05 +08:00
Zhenhua Zhang 3378e10c7c gdbus: Fix memory leak of service_data
Avoid the memory leak of server_data after service_reply has been
called.
2025-12-15 18:24:05 +08:00
Johan Hedberg 799db28a3f Fix parent path introspection data invalidation for multiple levels
In the case that parent path data needs to be invalidated we shouldn't
stop at the immediate parent if it doesn't have our own handler
registered but should continue upwards in the tree until we reach root
or our own handler.
2025-12-15 18:24:05 +08:00
Johan Hedberg b7dbb506b0 Fix memory leak in g_dbus_register_interface 2025-12-15 18:24:05 +08:00
Marcel Holtmann 2cb42ddf36 Make interface callback tables const 2025-12-15 18:24:05 +08:00
Vinicius Costa Gomes 7869a8b0a3 Fix the case when the requested name is already in use
We weren't setting the dbus error in this situation.
2025-12-15 18:24:05 +08:00
Vinicius Costa Gomes b7f18b4658 Fix: a pending call was leaking in check_service
This was triggering an assert inside libdbus when the timeout inside
the leaking pending call expired. The assert said that we were trying
to remove an nonexistent timeout.
2025-12-15 18:24:05 +08:00
Marcel Holtmann 97261500ac Remove unneeded use of status variable 2025-12-15 18:24:05 +08:00
Forrest Zhao 3118967460 Introduce g_dbus_setup_private() to gdbus
g_dbus_setup_private() is used to setup private DBusConnection
2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz 3f2a1322e2 Fix regression when removing watches
filter_data_find return the first data registered in this case so there is
no guarantee that it return the same data as passed to
filter_data_remove_callback which is the one that should be removed.

The fix is to simple cache the connection removing the correct data before
checking if there is any filter left.
2025-12-15 18:24:05 +08:00
Marcel Holtmann 2769107430 Cleanup of D-Bus mainloop integration 2025-12-15 18:24:05 +08:00
Marcel Holtmann 123ea2203f Update copyright information of D-Bus helper library 2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz 21f789b8d7 Fix undefined symbols 2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz ba7aad615c Port gdbus to use g_dbus_add_signal_watch 2025-12-15 18:24:05 +08:00
Luiz Augusto Von Dentz 5ff12d0e8f Add initial implementation of g_dbus_add_signal_watch
With g_dbus_add_signal_watch there is no need to register multiple filters
for dbus nor add matching rules manually.
2025-12-15 18:24:05 +08:00
Daniel Orstadius 02a0d1c308 Fix D-Bus timeout handling
Timeouts should also be removed in the remove_timeout callback in
addition to the timeout_handler_free function. This is how dbus-glib
does it and it seems to prevent crashes in certain situations.
2025-12-15 18:24:05 +08:00
Claudio Takahasi 467c3e623e Fix message handling for autostart.
Current implementation of libdbus Request name is blocking, consequently
the first incomming message that triggered the service autostart is not
being processed properly.
2025-12-15 18:24:05 +08:00
RISKÓ Gergely 2cb8f33a03 gdbus: handle introspection generally in generic_message.
Previously it was a specific case, now introspection is just another
interface, which is always implemented.  It is registered/unregistered
when an object path is referenced first/last.
2025-12-15 18:24:05 +08:00
RISKÓ Gergely 38f7261caa Add introspection interface to the output of introspection calls
This provides better compatibility with some D-Bus clients, such as qdbus.
2025-12-15 18:24:05 +08:00
Marcel Holtmann 5a0ad136bc Switch to a full non-recursive build system 2025-12-15 18:24:04 +08:00
Johan Hedberg 9025385a6e Use NameHasOwner instead of ListNames for name checking 2025-12-15 18:24:04 +08:00
Marcel Holtmann 74035750e2 Fix blocking service watch initial connect handling 2025-12-15 18:24:04 +08:00
Denis Kenzior 2705df8945 Make the parent path invalidateable 2025-12-15 18:24:04 +08:00
Luiz Augusto von Dentz 06c06dc150 Fix crash when calling g_dbus_remove_watch from inside the watch callback. 2025-12-15 18:24:04 +08:00
Luiz Augusto von Dentz 1e5736a769 Fix g_dbus_remove_all_watches to remove all watches for the given connection. 2025-12-15 18:24:04 +08:00
Luiz Augusto von Dentz a0df1f3a4f Fix gdbus watch function not handling multiple dbus connections.
gdbus was only adding a message filter for the very first connection given
by the user, this caused a bug in agent registration since it has a diffent
connection than previous watches it won't detect agent disappearing from the
bus.
2025-12-15 18:24:04 +08:00
Johan Hedberg 5286617d17 Revert "Fix null dereference in gdbus/watch.c"
This reverts commit a963621f4fcbf0251fd65df0992d339278a78052 so that gdbus
updates from obexd can be merged.
2025-12-15 18:24:04 +08:00
Gustavo F. Padovan 7d7f73e130 Fix null dereference in gdbus/watch.c
If name or data->name is null we have a null dereference. Not name and
data->name.
2025-12-15 18:24:04 +08:00
Marcel Holtmann 23c299dc3f Check that interface name is provided 2025-12-15 18:24:04 +08:00
Marcel Holtmann 98d6b5b96d Update copyright information 2025-12-15 18:24:04 +08:00
Raymond Liu 2652feabc2 Check if path is valid before unregistering it 2025-12-15 18:24:04 +08:00
Marcel Holtmann 42bdabbefc Fix issue with signed/unsigned comparison 2025-12-15 18:24:04 +08:00
Marcel Holtmann f8a650ab98 Use tabs for indentation 2025-12-15 18:24:04 +08:00
Marcel Holtmann 95858d5190 Add missing gdbus function declarations 2025-12-15 18:24:04 +08:00
Marcel Holtmann 842be382da Change file headers for D-Bus helper library 2025-12-15 18:24:04 +08:00
Marcel Holtmann e862047d9d Don't expect reply when sending D-Bus messages 2025-12-15 18:24:04 +08:00
Marcel Holtmann 6ac941b099 Add function for checking if a service is present 2025-12-15 18:24:04 +08:00
Marcel Holtmann a1f4514a5a Add g_dbus_add_service_watch() implementation 2025-12-15 18:24:04 +08:00
Marcel Holtmann 06c6a3d60c Fix connection disconnect function 2025-12-15 18:24:04 +08:00
Marcel Holtmann d0507d99dc Change declaration of GDBusWatchFunction 2025-12-15 18:24:04 +08:00
Johan Hedberg 67c13e1b1e Implement support g_dbus_create_error_valist 2025-12-15 18:24:04 +08:00
Marcel Holtmann 13262739f5 Remove g_dbus_unregister_all_interfaces function 2025-12-15 18:24:04 +08:00
Marcel Holtmann 98bf2e3926 Revert wrong listner id counter offset 2025-12-15 18:24:04 +08:00
Marcel Holtmann 262ee738bd Avoid a watch id of 0 2025-12-15 18:24:04 +08:00
Marcel Holtmann 8c1b9c9e6d Move some D-Bus helpers around 2025-12-15 18:24:04 +08:00
Marcel Holtmann 5de73c0ce4 Don't abstract functions that are only used once 2025-12-15 18:24:04 +08:00
Marcel Holtmann 01fad8f214 Remove another unused function 2025-12-15 18:24:04 +08:00
Marcel Holtmann 72a2c6d38d Make helper function static and local 2025-12-15 18:24:04 +08:00
Marcel Holtmann fe3f118681 Remove unused defines 2025-12-15 18:24:04 +08:00
Marcel Holtmann 2b1a7bed35 Don't consider mainloop integration of dbus-glib 2025-12-15 18:24:04 +08:00
Marcel Holtmann 3e7be8ffd5 Remove another obsolete function 2025-12-15 18:24:04 +08:00
Marcel Holtmann 7909aade9c Add proper signal sending helpers 2025-12-15 18:24:03 +08:00
Marcel Holtmann bc04b2b674 Remove obsolete dbus_connection_get_object_user_data function 2025-12-15 18:24:03 +08:00
Marcel Holtmann cd32f0d4c9 Remove object path creation and destroy helpers 2025-12-15 18:24:03 +08:00
Marcel Holtmann 5929f451fd Remove obsolete D-Bus interface helpers 2025-12-15 18:24:03 +08:00
Marcel Holtmann 178caf3bf3 Remove obsolete D-Bus sending helpers 2025-12-15 18:24:03 +08:00
Marcel Holtmann e8004dcc51 Add simple g_dbus_unregister_all_interfaces implementation 2025-12-15 18:24:03 +08:00
Marcel Holtmann 33ddb45199 Add skeleton for g_dbus_unregister_all_interfaces 2025-12-15 18:24:03 +08:00
Marcel Holtmann 82487204bb Remove GDBusDisconnectFunction type 2025-12-15 18:24:03 +08:00
Johan Hedberg c88da8f4fb Change name_listener API to libgdbus watch API 2025-12-15 18:24:03 +08:00
Marcel Holtmann a06c2bf95e Add helpers for sending async replies 2025-12-15 18:24:03 +08:00
Marcel Holtmann 41a68a1704 Add helpers for creating replies 2025-12-15 18:24:03 +08:00
Marcel Holtmann 80a40e4bc1 Fix broken signal checking for new style API 2025-12-15 18:24:03 +08:00
Marcel Holtmann 8c20dd4094 Add helpers for error creation 2025-12-15 18:24:03 +08:00
Marcel Holtmann ae9735d8ec More fixes for the message dispatch handling 2025-12-15 18:24:03 +08:00
Marcel Holtmann b0842bfd31 Add new message dispatching 2025-12-15 18:24:03 +08:00
Marcel Holtmann c008c770d3 Fix object path reference count handling 2025-12-15 18:24:03 +08:00
Marcel Holtmann 3645f00aec Add introspection support for new interface handlers 2025-12-15 18:24:03 +08:00
Marcel Holtmann 7aebce13e4 Use reference counting for the object paths 2025-12-15 18:24:03 +08:00
Marcel Holtmann 4e2ff8a42d Add first implementation of libgdbus interface helpers 2025-12-15 18:24:03 +08:00
Marcel Holtmann b8094a462a Add prototypes for interface registration 2025-12-15 18:24:03 +08:00
Marcel Holtmann fa8baad6b0 Add real libgdbus types for interface definitions 2025-12-15 18:24:03 +08:00
Marcel Holtmann 5cc51c7078 Move D-Bus object and interface helpers into libgdbus 2025-12-15 18:24:03 +08:00
Marcel Holtmann a34894b7da Move D-Bus watch functions into libgdbus 2025-12-15 18:24:03 +08:00
Marcel Holtmann aca2ce7cb6 Emulate libgdbus API for mainloop integration 2025-12-15 18:24:03 +08:00
Marcel Holtmann 1c4c651c63 Move D-Bus mainloop integration into libgdbus 2025-12-15 18:24:03 +08:00
Marcel Holtmann a446318b57 Add skeleton for libgdbus support 2025-12-15 18:24:03 +08:00
Marcel Holtmann 011f5c8ca9 Add directory for libgdbus library 2025-12-15 18:24:03 +08:00
openvela-robot 1635c81efd 3dde8c07998f0c9c7f9689495eb2690cc3f5a924
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:03 +08:00
openvela-robot 68f7fd9961 kvdb/client: fix monitor fd leak
Signed-off-by: chao an <anchao@xiaomi.com>
2025-12-15 18:24:03 +08:00
Xiang Xiao fcdaa0a743 utils: Add the basic android header files
include/android/log.h:
include/log/:
include/private/android_logger.h
  system/logging/

include/android/set_abort_message.h:
  bionic/libc/include/android/set_abort_message.h

include/cutils/trace.h:
  system/core/libcutils/include/cutils/trace.h

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:02 +08:00
Xiang Xiao cf50ea1eca Add include to the public search path
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:02 +08:00
jihandong 1905297463 frameworks: rm app_focus
dependson:888406

Signed-off-by: jihandong <jihandong@xiaomi.com>
2025-12-15 18:24:02 +08:00
Xiang Xiao 735198da58 Revert "Add include to the public search path"
This reverts commit 26be12ebd2f669d38782ca3911c225e9f2a0644d.
2025-12-15 18:24:02 +08:00
Xiang Xiao b604114074 gdbus: remove glib header file from gdbus.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:02 +08:00
Xiang Xiao 9e0274a552 Revert "framework/gdbus: remove glib header file from gdbus.h"
This reverts commit 611fddab6fa2c183170a14811206546df6e6728f.
2025-12-15 18:24:02 +08:00
openvela-robot 0753f3b855 Add include to the public search path
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:02 +08:00
ligd 5b5962d868 kvdb: handle server refused by backlog limitation
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:02 +08:00
openvela-robot 0675feaf6b kvdb: add kvdb xx_oneway API
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:02 +08:00
dongjiuzhu1 e1d9aaa3cd framework/gdbus: using LIB_DBUS to replace DBUS_HELPER_LIBRARY
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:02 +08:00
dongjiuzhu1 019fc1bef7 framework/gdbus: remove glib header file from gdbus.h
Change gboolean to bool, guint to unsigned int, guint32 to uint32_t

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:02 +08:00
dongjiuzhu1 fe905a310f framework/gdbus: remove prefix g_ for gdbus api.
1. Remove prefix g_ for all gdbus api
2. Using macro to compatible g_ gdus api

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:02 +08:00
openvela-robot 35a9155688 framework/gdbus: initial version for D-Bus heleper library
Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:02 +08:00
wangbowen6 7de89c5f72 client: bug fix, should assgin '\0' to newvalue[0] instead newvalue
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:01 +08:00
wangbowen6 0511bb8de6 kvdb: [bug fix] memory use after free and ret should be signd num
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:01 +08:00
wangbowen6 a9633d030d kvdb: add kvdb monitor support
Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot e2c7c43f3a kvdb: fix property_list exit early problem
when the kvdb has too many kv pairs, after kvdb_list_consume()
blocked in sendmsg (write buffer not enough), the domain socket
buffer layout may became:
[k0_len][v0_len][k0][v0]...[kn_len][vn_len][kn][vn][the last char]
so the client property_list will receive only one char (ret = 1)
after received [k0, v0] ~ [kn, vn], but actually the property list
is not terminated, property_list exit early problem happened.

this problem can be easily reproduced in 86panel by running kvdb
testcase twice.

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot abf21c6560 frameworks/utils: move bin path to apps/staging
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot a9549ca708 frameworks/kvdb: move bin path to apps/staging
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot f69f1f4058 frameworks/utils: create bin to current directory
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot fe0392a514 frameworks/kvdb: create bin to current directory
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
openvela-robot 4f187d2f88 utils: build utils lib into vendor/bes/boards.. from source for m0
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
haopengxiang bc28e21cec kvdb: build kvdb libs into vendor/bes/boards.. from source for m0
Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:01 +08:00
Peter Bee d83d25d538 frameworks/kvdb: unify sizeof() usage
... in hope for eliminating suspicion from CodeChecker

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:24:01 +08:00
wangbowen6 516727006b client: property_set/get_buffer() bug fix
loop condition error

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
2025-12-15 18:24:00 +08:00
Xiang Xiao 15a721ddc3 Move kbdb.h to include directory
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
Peter Bee 62985d3573 frameworks/kvdb: fix getprop long kv fail on sim
Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:24:00 +08:00
chao.an 7747bb4f1d external: move nuttx role files uppper to external
Signed-off-by: chao.an <anchao@xiaomi.com>
2025-12-15 18:24:00 +08:00
Xiang Xiao 1566a11c50 frameworks/kvdb: add property_set_buffer and property_get_buffer
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
Jiuzhu Dong 01e0658403 frameworks/kvdb: using CLOCK_MONOTONIC to avoid time sync
Signed-off-by: Jiuzhu Dong <dongjiuzhu1@xiaomi.com>
2025-12-15 18:24:00 +08:00
huxiandong 4c2e61e80d kvdb: fix read first path error.
Signed-off-by: huxiandong <huxiandong@xiaomi.com>
2025-12-15 18:24:00 +08:00
ligd cf2916d758 kvdb: fix kvdb error modify const data
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:00 +08:00
ligd 367c91fc06 kvdb: fix kvdb error modify const data
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:00 +08:00
ptr_b 60fb6dfb4e frameworks/kvdb: update desc to doxygen style
Signed-off-by: ptr_b <bijunda1@xiaomi.com>
2025-12-15 18:24:00 +08:00
Peter Bee dc7db12af0 frameworks/kvdb: enhance checks
fix Coverity warnings:
check key != NULL (NULL pointer dereference)
check recv length (overrun buffer arg)

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:24:00 +08:00
ligd 2c9d3acbe9 kvdb: remove kvdb list thread
dependson:818316

For list thread will caused mulit-threads access same list of
mem_hash_cursor, if one do the list, other one do delete, then
there will be error.

The typical app is:
call kvdb_delete in kvdb_list callback

Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:24:00 +08:00
Xiang Xiao 527357081b Fix server.c:127:9: warning: argument 1 null where non-null expected
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
chao.an 759578bc75 kvdb/client: fix reload/commit fd leak
Signed-off-by: chao.an <anchao@xiaomi.com>
2025-12-15 18:24:00 +08:00
chao.an 53728ddd40 kvdb/server: reassemble received data to ensure consistency
Signed-off-by: chao.an <anchao@xiaomi.com>
2025-12-15 18:24:00 +08:00
openvela-robot 669702b0c9 fix: optimize default load multi kvdb source files
Signed-off-by: huxiandong <huxiandong@xiaomi.com>
2025-12-15 18:24:00 +08:00
haopengxiang 9266e989fa app focus: add focus_customize value in focus_id for user
1. add focus_customize in focus_id struct
2. extend app_focus_stack_display for more details

Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
haopengxiang 9b78ad0301 app focus: basic module for different focus frameworks
update config description and use list_node as head node

Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
haopengxiang 9c39af1525 Revert "app focus: use list_node as head node"
This reverts commit 6c4b115af4577cbae027b70d09be8af1214e4745.

Reason for revert: Kconfig needs to be updated
2025-12-15 18:24:00 +08:00
openvela-robot 2eddade7d5 app focus: use list_node as head node
remove only interface app_focus_request for method simplification.

Signed-off-by: haopengxiang <haopengxiang@xiaomi.com>
2025-12-15 18:24:00 +08:00
liuhaitao 5241de2d4a kvdb: support load from multiple source pathes
Use semicolon ';' to split source pathes. For example,
/etc/build.prop;/misc/factory.prop

Signed-off-by: liuhaitao <liuhaitao@xiaomi.com>
2025-12-15 18:23:59 +08:00
chentao9 ba0571ffb8 refactor: kvdb: add force sync flag for kvdb load
1.for kvdb init,do not need force sync existed kv
2.for property_reload api,it will force sync existed kv

Signed-off-by: chentao9 <chentao9@xiaomi.com>
2025-12-15 18:23:59 +08:00
chentao9 28d41782a7 feature: kvdb: add initial value reload support
if the initial value file has been modified,use api 'propprop_reload' to refresh initial value of kvdb

Signed-off-by: chentao9 <chentao9@xiaomi.com>
2025-12-15 18:23:59 +08:00
liuhaitao 092482fe02 kvdb: increases kvdb default stack size from 2K to 4K
Kvdbd server should use 4K stack size to work.

Signed-off-by: liuhaitao <liuhaitao@xiaomi.com>
2025-12-15 18:23:59 +08:00
ligd c7dffc852d kvdb: recv should handle return 0 in property_list()
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:23:59 +08:00
ligd 80ed6b0d64 kvdb: simplify KVDB marco in Kconfig
Signed-off-by: ligd <liguiding1@xiaomi.com>
2025-12-15 18:23:59 +08:00
liuhaitao 7e5c08654b kvdb: correct to use PROP_VALUE_MAX for property value
Signed-off-by: liuhaitao <liuhaitao@xiaomi.com>
2025-12-15 18:23:59 +08:00
Xiang Xiao d7fe92f930 kvdb: extend the length of name and value to 127 and 255
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:23:59 +08:00
Xiang Xiao 256942fb22 kvdb: handle name or value length beyond 128 correctly
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:23:59 +08:00
openvela-robot d01f202cfa frameworks/kvdb: fix recv() logic in property_list
Fix handling logic when local socket pipe is full, server is
blocked and client does not receive the whole message. The client now
waits for the whole message to be received instead of disspecific productding it and
continue, which will break the communication afterwards.

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:59 +08:00
openvela-robot afbe799688 Initial empty repository 2025-12-15 18:23:59 +08:00
zhanghu b2ae794dd7 kvdb warning: suggest parentheses 2025-12-15 18:23:59 +08:00
Xiang Xiao b6ace1c58d frameworks/kvdb: Add Android compatible header file
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:23:59 +08:00
Peter Bee ef183f04cd frameworks/kvdb: add -h argument for help
N/A

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:59 +08:00
Peter Bee 97df2e7fd1 frameworks/kvdb: add remote server support
N/A

Enable rpmsg socket support for AMP use case

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:59 +08:00
Peter Bee 3ce85f5126 frameworks/kvdb: add API for actively commit props
N/A
add property_commit() to skip commit intervals

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:59 +08:00
chao.an 07bb08198c kvdb: include able from cxx files
Signed-off-by: chao.an <anchao@xiaomi.com>
2025-12-15 18:23:59 +08:00
Peter Bee 0f4991d813 frameworks/kvdb: fix read-only properties init
N/A

Now read-only properties init as expected

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
openvela-robot 6ad14e6c29 Merge "commit the change after loading" into dev 2025-12-15 18:23:58 +08:00
Xiang Xiao f74fed702c commit the change after loading
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 432ec45fb8 frameworks/kvdb: disable journal to accelerate
Disabling unqlite journal, now periodical commit() works as desired

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 9371145001 frameworks/kvdb: load default values if not set
N/A

Load default values depending on whether the value has been set or not,
instead of whether the whole db has existed.

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 8c92342a7f frameworks/kvdb: fix list only list 1 persist prop
N/A

Unqlite expect data consumer to return 0, otherwise it will return
UNQLITE_CORRUPT(-10), which resulted in previous getprop only listing
one persistent property.

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 930be27403 frameworks/kvdb: fix build break
N/A

fix include sys/time.h

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee f0cc12c0b1 frameworks/kvdb: add kvdb server version
add background kvdb server task to speed up I/Os
use unix domain socket for IPC (currently SOCK_STREAM)
add background auto commit interval by select()
use individual thread for property_list

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
chao.an 4c47526729 kvdb: add NULL default value support
N/A

Signed-off-by: chao.an <anchao@xiaomi.com>
2025-12-15 18:23:58 +08:00
Xiang Xiao 6d996e1a1e kvdb: try property_get from environment variable first
N/A

will hook property_list later once get_environ_ptr get implemented

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2025-12-15 18:23:58 +08:00
liuhaitao 46fe2cbddc kvdb: make ro.* properties modified and deleted not permitted
N/A

Signed-off-by: liuhaitao <liuhaitao@xiaomi.com>
2025-12-15 18:23:58 +08:00
liuhaitao 81e2c85dab frameworks/kvdb: update persist.* props behaviour
N/A

persist.* props saved into /data/kv.db instead of using
/persist/kv.db. And all other props saved into /tmp/kv.db.
And all in-memory and user databases default values read
from /etc/build.prop in uniform.

Signed-off-by: liuhaitao <liuhaitao@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 15bcd284b9 frameworks/kvdb: fix property_list return value
Add logic to return -ENOSPC when failed to open all databases.

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee c84a1c15df frameworks/kvdb: fix cli ret judge logic
N/A

property_get error case is when ret==strlen(default_value), not ret < 0

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
Peter Bee 91cdf35900 framework/kvdb: Add kvdb APIs and CLI tools
APIs for setting and getting Key-Value pairs
	CLI tools for command line debugging
	changed API to Android style

Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2025-12-15 18:23:58 +08:00
62 changed files with 9548 additions and 0 deletions

View File

@ -0,0 +1,40 @@
name: 缺陷反馈 | Bug
description: 当您发现了一个缺陷,需要向社区反馈时,请使用此模板。
title: "[BUG] <标题>"
labels: [👀 needs triage, "Type: Bug"]
body:
- type: markdown
attributes:
value: |
感谢您对 openvela 社区的支持与关注,欢迎反馈缺陷。
- type: textarea
attributes:
label: "重现问题的步骤"
description: "简洁地描述错误是什么,为什么您认为它是一个错误,以及如何重现它的步骤"
placeholder: |
重现问题的步骤,可能包括日志和截图。
1. 步骤 1
2. 步骤 2
validations:
required: true
- type: dropdown
id: architecture
attributes:
label: Issue Architecture
multiple: true
options:
- "Arch: arm"
- "Arch: arm64"
- "Arch: x86_64"
validations:
required: true
- type: markdown
attributes:
value: |
提交前请确认您已遵循以下步骤:
- 确认问题在 [**dev**](../) 上可重现。
- 遇到构建问题时运行 `make distclean`。
- 搜索 [现有问题](./)

View File

@ -0,0 +1,34 @@
name: 新需求 | Feature
description: 当您需要反馈或实现一个新需求时,使用此模板。
title: "[FEATURE] <标题>"
body:
- type: markdown
attributes:
value: |
感谢您对 openvela 社区的支持与关注。
- type: textarea
id: question-description
attributes:
label: 您的需求是否和问题相关?
description: 请简单描述问题并提供issue链接。
validations:
required: true
- type: textarea
id: solution
attributes:
label: 请描述您想要的解决方案
validations:
required: true
- type: textarea
id: 替代方案
attributes:
label: 请描述您考虑过的替代解决方案
- type: markdown
attributes:
value: |
提交前请搜索 [现有功能需求](./)

View File

@ -0,0 +1,22 @@
name: 问题咨询
title: "[问题咨询]"
body:
- type: markdown
attributes:
value: |
感谢您对 openvela 社区的支持与关注。
- type: textarea
id: question-description
attributes:
label: 描述
description: 请解释您的问题的背景或上下文,这有助于其他人更好地理解您的问题或疑问。
validations:
required: true
- type: markdown
attributes:
value: |
提交前请确认您已遵循以下步骤:
- 我已搜索 [openvela 文档](../),但未找到问题的答案。
- 已搜索 [现有问题](./)

View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -0,0 +1,11 @@
## 概要
*在此部分更新信息,说明更改的必要性、具体做了什么以及如何实现的,如果有新功能出现,请提供参考资料(依赖关系、类似问题和解决方案等)。*
## 影响
*在此部分更新信息(如适用),说明更改如何影响用户、构建过程、硬件、文档、安全性、兼容性等。*
## 测试
*在此部分更新信息详细说明如何验证更改使用什么主机进行构建操作系统、CPU、编译器等使用什么目标进行验证架构、板子配置等。提供更改前后的构建和运行日志将非常有帮助。*

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @xiaoxiang781216 @GUIDINGLI @huangcaihua-xm

View File

@ -0,0 +1,60 @@
# 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.
#
name: Bug report
description: Report a bug to improve openvela stability
title: "[BUG] <title>"
labels: [👀 needs triage, "Type: Bug"]
body:
- type: markdown
attributes:
value: |
Hello openvela Community member! Please keep things tidy by putting your post in the proper place:
Reporting a bug: use this form.
Asking a question or getting help: use the [General Help](./new?assignees=&labels=Community%3A+Question&projects=&template=003_help.yml&title=%5BHELP%5D+%3Ctitle%3E) form.
Requesting a new feature: use the [Feature request](./new?assignees=&labels=Type%3A+Enhancement&projects=&template=002_feature_request.yml&title=%5BFEATURE%5D+%3Ctitle%3E) form.
- type: textarea
attributes:
label: "Description / Steps to reproduce the issue"
description: "A clear and concise description of what the bug is, and why you consider it to be a bug, and steps for how to reproduce it"
placeholder: |
A description with steps to reproduce the issue.
May include logs, images, or videos.
1. Step 1
2. Step 2
validations:
required: true
- type: dropdown
id: architecture
attributes:
label: Issue Architecture
description: What architecture(s) are you seeing the problem on?
multiple: true
options:
- "[Arch: arm]"
- "[Arch: arm64]"
- "[Arch: x86_64]"
validations:
required: true
- type: markdown
attributes:
value: |
### Before You Submit
Please verify that you've followed these steps:
- Confirm the problem is reproducible on [**dev**](../).
- Run `make distclean` when encountering build issues.
- Search [existing issues](./) (including [closed](./?q=is%3Aissue+is%3Aclosed))

View File

@ -0,0 +1,55 @@
# 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.
#
name: Feature request
description: Request an enhancement for openvela
title: "[FEATURE] <title>"
labels: ["Type: Enhancement"]
body:
- type: markdown
attributes:
value: |
Hello openvela Community member! Please keep things tidy by putting your post in the proper place:
Requesting a new feature: use this form.
Asking a question or getting help: use the [General Help](./new?assignees=&labels=Community%3A+Question&projects=&template=003_help.yml&title=%5BHELP%5D+%3Ctitle%3E) form.
Reporting a bug: use the [Bug report](./new?assignees=&labels=%F0%9F%91%80+needs+triage%2CType%3A+Bug&projects=&template=001_bug_report.yml&title=%5BBUG%5D+%3Ctitle%3E) form.
- type: textarea
id: question-description
attributes:
label: Is your feature request related to a problem? Please describe.
description: Please provide a clear and concise description of what the problem is. Add relevant issue link.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: Please provide a clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: Please provide a clear and concise description of any alternative solutions or features you've considered.
- type: markdown
attributes:
value: |
### Before You Submit
Please verify that you've followed these steps:
- Search [existing feature requests](./) (including [closed](./?q=is%3Aissue+is%3Aclosed))

47
.github/ISSUE_TEMPLATE/003_help.yml vendored Normal file
View File

@ -0,0 +1,47 @@
# 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.
#
name: General Help
description: Get general support regarding openvela
title: "[HELP] <title>"
labels: ["Community: Question"]
body:
- type: markdown
attributes:
value: |
Hello openvela Community member! Please keep things tidy by putting your post in the proper place:
Asking a question or getting help: use this form.
Reporting a bug: use the [Bug report](./new?assignees=&labels=%F0%9F%91%80+needs+triage%2CType%3A+Bug&projects=&template=001_bug_report.yml&title=%5BBUG%5D+%3Ctitle%3E) form.
Requesting a new feature: use the [Feature request](./new?assignees=&labels=Type%3A+Enhancement&projects=&template=002_feature_request.yml&title=%5BFEATURE%5D+%3Ctitle%3E) form
- type: markdown
attributes:
value: |
### Whether you're a beginner or an experienced developer, openvela Help is here to assist you with all your openvela questions and concerns.
- type: textarea
id: question-description
attributes:
label: Description
description: Explain the background or context of your question. This helps others understand your problem or inquiry better.
validations:
required: true
- type: markdown
attributes:
value: |
### Before You Submit
Please verify that you've followed these steps:
- I have searched [openvela Documentation](../) and didn't find an answer to my question.
- Search [existing issues](./) (including [closed](./?q=is%3Aissue+is%3Aclosed))

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

20
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,20 @@
*Note: Please adhere to [Contributing Guidelines](https://github.com/open-vela/docs/blob/dev/CONTRIBUTING.md).*
## Summary
*Update this section with information on why change is necessary,
what it exactly does and how, if new feature shows up, provide
references (dependencies, similar problems and solutions), etc.*
## Impact
*Update this section, where applicable, on how change affects users,
build process, hardware, documentation, security, compatibility, etc.*
## Testing
*Update this section with details on how did you verify the change,
what Host was used for build (OS, CPU, compiler, ..), what Target was
used for verification (arch, board:config, ..), etc. Providing build
and runtime logs from before and after change is highly appreciated.*

14
.github/workflows/checkpatch.yml vendored Normal file
View File

@ -0,0 +1,14 @@
# This is a basic workflow to help you get started with Actions
name: checkpatch
# Controls when the workflow will run
on:
pull_request:
types: [opened, reopened, synchronize]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
checkpatch:
uses: open-vela/public-actions/.github/workflows/checkpatch.yml@dev
secrets: inherit

16
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,16 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
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:
ci:
uses: open-vela/public-actions/.github/workflows/ci.yml@dev
secrets: inherit

13
.github/workflows/clang-format.yml vendored Normal file
View File

@ -0,0 +1,13 @@
# This is a basic workflow to help you get started with Actions
name: clang-format
# Controls when the workflow will run
on:
pull_request:
types: [opened, reopened, synchronize]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
clang-format:
uses: open-vela/public-actions/.github/workflows/clang-format.yml@dev

11
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: 'Close stale issues and PR'
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch: # 允许手动触发
jobs:
stale:
uses: open-vela/public-actions/.github/workflows/stale.yml@dev
secrets: inherit

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/uv
*.o
Make.dep
.depend
.built

118
Android.bp Normal file
View File

@ -0,0 +1,118 @@
cc_defaults {
name: "framework_utils_defaults",
static_libs: [
"libframework_utils",
],
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",
],
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",
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",
],
}
cc_library_headers {
name: "libprop_headers",
export_include_dirs: ["include/cutils"],
vendor_available: true,
}
cc_library_headers {
name: "libframework_utils_headers",
export_include_dirs: ["include"],
vendor_available: true,
}
cc_binary {
name: "kvset",
srcs: ["kvdb/setprop.c"],
defaults: ["framework_utils_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
}

159
CMakeLists.txt Normal file
View File

@ -0,0 +1,159 @@
#
# Copyright (C) 2021 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.
#
if(CONFIG_SCHED_INSTRUMENTATION_DUMP
OR CONFIG_ANDROID_LIBBASE
OR CONFIG_ATRACE
OR CONFIG_LIB_DBUS
OR CONFIG_KVDB)
set_property(
TARGET nuttx
APPEND
PROPERTY NUTTX_INCLUDE_DIRECTORIES
${NUTTX_APPS_DIR}/frameworks/system/utils/include)
set(CSRCS)
set(CFLAGS)
set(INCDIR)
nuttx_add_library(framework_utils STATIC)
list(APPEND CSRCS trace/trace.c)
if(CONFIG_ANDROID_LIBBASE)
list(APPEND CSRCS log/log_write.c log/set_abort_message.c)
endif()
if(CONFIG_ATRACE)
nuttx_add_application(NAME atrace SRCS trace/atrace.c DEPENDS
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)
if(CONFIG_KVDB_NVS)
list(APPEND CSRCS kvdb/nvs.c)
elseif(CONFIG_KVDB_UNQLITE)
list(APPEND INCDIR ${NUTTX_APPS_DIR}/external/unqlite/unqlite)
list(APPEND CSRCS kvdb/unqlite.c)
endif()
if(CONFIG_KVDB_FILE OR CONFIG_KVDB_TEMPORARY_STORAGE)
list(APPEND CSRCS kvdb/file.c)
endif()
if(CONFIG_KVDB_SERVER)
nuttx_add_application(
MODULE
${CONFIG_KVDB}
NAME
kvdbd
STACKSIZE
${CONFIG_KVDB_STACKSIZE}
PRIORITY
${CONFIG_KVDB_PRIORITY}
SRCS
kvdb/server.c
INCLUDE_DIRECTORIES
${INCDIR}
DEPENDS
framework_utils)
endif()
nuttx_add_application(
MODULE
${CONFIG_KVDB}
NAME
setprop
STACKSIZE
${CONFIG_KVDB_STACKSIZE}
PRIORITY
${CONFIG_KVDB_PRIORITY}
SRCS
kvdb/setprop.c
INCLUDE_DIRECTORIES
${INCDIR}
DEPENDS
framework_utils)
nuttx_add_application(
MODULE
${CONFIG_KVDB}
NAME
getprop
STACKSIZE
${CONFIG_KVDB_STACKSIZE}
PRIORITY
${CONFIG_KVDB_PRIORITY}
SRCS
kvdb/getprop.c
INCLUDE_DIRECTORIES
${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})
target_include_directories(framework_utils PRIVATE ${INCDIR})
target_compile_options(framework_utils PRIVATE ${CFLAGS})
endif()

179
Kconfig Normal file
View File

@ -0,0 +1,179 @@
#
# Copyright (C) 2020 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.
#
config ALOG
bool "Enable Android Log"
default n
select LIBC_PRINT_EXTENSION
config ALOG_LEVEL
int "Android Log level"
default 0 if NDEBUG
default 3 if !NDEBUG
depends on ALOG
range 0 6
---help---
ALOG_LEVEL is used to control the logging level for printing.
0:LOG_ALWAYS_FATAL
1:LOG_FATAL
2:LOG_ERROR
3:LOG_WARN
4:LOG_INFO
5:LOG_DEBUG
6:LOG_VERBOSE
config ATRACE
bool "Android Trace"
default n
---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
if KVDB
choice
prompt "KVDB log level"
default KVDB_LOG_SLIENT
config KVDB_LOG_INFO
bool "KVDB_LOG_INFO"
config KVDB_LOG_WARN
bool "KVDB_LOG_WARN"
config KVDB_LOG_ERR
bool "KVDB_LOG_ERR"
config KVDB_LOG_SLIENT
bool "KVDB_LOG_SLIENT"
endchoice
config KVDB_PRIORITY
int "task priority"
default 100
config KVDB_STACKSIZE
int "stack size"
default 4096
config KVDB_DUMPLIST
bool "KVDB dump list"
default y
---help---
Kvd will dump all key-value when use getprop without key
config KVDB_SERVER
bool "KVDB server"
default n
---help---
Build kvdb in server mode. Operate database in a unified manner through the kvdb server
config KVDB_DIRECT
bool "Access KVDB directly"
depends on !KVDB_SERVER
---help---
Operate the database directly. Applicable to scenarios where cross-core communication is not required
if !KVDB_DIRECT
config KVDB_SERVER_CPUNAME
string "which cpu kvdb server runs on"
depends on !KVDB_SERVER
default "ap"
config KVDB_TIMEOUT_INTERVAL
int "transaction timeout interval(sec)"
default 0
endif
config KVDB_COMMIT_INTERVAL
int "commit time interval(sec)"
depends on KVDB_SERVER
default 5
config KVDB_BACKLOG_CONNS
int "backlog connections"
depends on KVDB_SERVER
default 32
if KVDB_DIRECT || KVDB_SERVER
config KVDB_SOURCE_PATH
string "database default value source path"
default "/etc/build.prop"
config KVDB_TEMPORARY_STORAGE
bool "enable non-persistent Key-value storage"
default !DEFAULT_SMALL
depends on FS_TMPFS
choice
prompt "the persistent storage method of Key-value"
default KVDB_UNQLITE
config KVDB_UNQLITE
bool "UNQLITE"
depends on UNQLITE
---help---
Configure the unqlite database to store Key-value.
config KVDB_NVS
bool "NVS"
depends on MTD_CONFIG_NAMED
---help---
Configure using Non-Volatile Storage to store Key-value
config KVDB_FILE
bool "FILE"
---help---
Configure using file to store Key-value
endchoice
config KVDB_PERSIST_PATH
string "persistent database path"
default "/data/persist.db" if KVDB_UNQLITE
default "/dev/config" if KVDB_NVS
config KVDB_TEMPORARY_PATH
string "non-persistent database directory path"
default "/tmp/db"
depends on KVDB_TEMPORARY_STORAGE
endif # KVDB_DIRECT || KVDB_SERVER
config KVDB_QEMU_PROPERTIES
tristate "Goldfish boot-properties service"
default n
depends on GOLDFISH_PIPE
---help---
Enable the Goldfish boot-properties service
endif # KVDB
osource "$APPSDIR/frameworks/system/utils/uv/Kconfig"

10
LICENSE Normal file
View File

@ -0,0 +1,10 @@
Copyright (C) 2024 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.

27
Make.defs Normal file
View File

@ -0,0 +1,27 @@
#
# Copyright (C) 2021 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.
#
ifneq ($(CONFIG_SCHED_INSTRUMENTATION_DUMP)\
${CONFIG_ANDROID_LIBBASE}\
${CONFIG_ATRACE}\
${CONFIG_LIB_DBUS}\
${CONFIG_KVDB},)
CONFIGURED_APPS += $(APPDIR)/frameworks/system/utils
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/frameworks/system/utils/include
CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/frameworks/system/utils/include
endif
-include $(APPDIR)/frameworks/system/utils/uv/Make.defs

77
Makefile Normal file
View File

@ -0,0 +1,77 @@
#
# Copyright (C) 2021 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 $(APPDIR)/Make.defs
CSRCS += trace/trace.c
ifneq ($(CONFIG_ANDROID_LIBBASE),)
CSRCS += log/log_write.c log/set_abort_message.c
endif
ifneq ($(CONFIG_ATRACE),)
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
else
CSRCS += kvdb/client.c
MAINSRC += kvdb/exitprop.c
PROGNAME += exitprop
endif # CONFIG_KVDB_DIRECT
CSRCS += kvdb/common.c kvdb/system_properties.c kvdb/backend.c
MAINSRC += kvdb/setprop.c kvdb/getprop.c
PROGNAME += setprop getprop
ifneq ($(CONFIG_KVDB_SERVER),)
MAINSRC += kvdb/server.c
PROGNAME += kvdbd
endif # CONFIG_KVDB_SERVER
ifneq ($(CONFIG_KVDB_NVS),)
CSRCS += kvdb/nvs.c
else ifneq ($(CONFIG_KVDB_UNQLITE),)
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/external/unqlite/unqlite
CSRCS += kvdb/unqlite.c
endif # CONFIG_KVDB_NVS
ifneq ($(CONFIG_KVDB_FILE)$(CONFIG_KVDB_TEMPORARY_STORAGE),)
CSRCS += kvdb/file.c
endif # CONFIG_KVDB_FILE or CONFIG_KVDB_TEMPORARY_STORAGE
ifneq ($(CONFIG_KVDB_QEMU_PROPERTIES),)
MAINSRC += kvdb/qemu_properties.c
PROGNAME += qemuprop
endif # CONFIG_KVDB_QEMU_PROPERTIES
PRIORITY = $(CONFIG_KVDB_PRIORITY)
STACKSIZE = $(CONFIG_KVDB_STACKSIZE)
MODULE = $(CONFIG_KVDB)
endif # CONFIG_KVDB
EXPORT_FILES := gdbus/gdbus.h include
include $(APPDIR)/Application.mk

254
README.md Normal file
View File

@ -0,0 +1,254 @@
# Utils
[[English](./README.md) | [中文](./README_zh-cn.md)]
## Project Overview
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`. |
| `trace` | Provides a dotting tool for user-space programs. |
## Project Description
### 1. gdbus
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`.
### 2. kvdb
#### 2.1 Introduction
`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)
#### 2.2 Typical configuration of `kvdb`
| 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. |
> Only one of the three backends for data storage, `CONFIG_KVDB_UNQLITE`, `CONFIG_KVDB_NVS`, and `CONFIG_KVDB_FILE`, can be selected.
### 3. 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:
```log
android log api
|
\|/
log wrapper
|
\|/
vela log impl
```
### 4. 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.
## Usage Guide
### 1. gdbus
1. To enable the `CONFIG_LIB_DBUS` build option
2. Instantiation
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:
```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.
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)
{
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);
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;
}
```
### 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.
```c
#include <log/log.h>
// the tag for the ALOGI
#define LOG_TAG "MyAppTag"
int main() {
// print log with custom priority level
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Formatted number: %d", 42);
// Using ALOGI macro to print info level log
ALOGI("ALOGI: A log message from my app.");
return 0;
}
```
### 4. 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>
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
```
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.

281
README_zh-cn.md Normal file
View File

@ -0,0 +1,281 @@
# Utils
[[English](./README.md) | [中文](./README_zh-cn.md)]
## 项目概览
当前目录下包含的主要是framework当中提供的一些常用工具实现.
| 工具 | 工具简要描述 |
| -- | -- |
| `gdbus` | 对`D-Bus`接口封装, 方便操作`D-Bus` |
| `kvdb` | 基于本地数据库的`键值对`数据存取接口 |
| `log` | 提供和`Android`平台兼容的`Log API`接口<br>用于在`Vela`当中直接使用`Android` LOG API |
| `trace` | 提供用于用户空间程序的打点工具 |
## 项目描述
### 1. gdbus
`gdbus`模块是对`D-Bus`接口的进一步封装的API模块. 由于`D-Bus`接口使用比较复杂, 在实际模块使用时, 通过将`D-Bus`接口再次封装, 会方便使用. `gdbus`通过提供更简易操作的API接口方便我们去操作`D-Bus`.
### 2. kvdb
#### 2.1 简要介绍
`kvdb`提供了一套本地数据库的读写接口, `API`设计参考`Android`的`properties`存取规范, 同时提供了命令行工具以方便本地快速调试.
`Vela`中的`kvdb`支持本地永久化存储以及跨核调用(分别需要Unix domain socket和rpmsg socket支持), 需要永久存储到文件的键值需要以`"persist."`开头.
`kvdb`底层实现包含了三种机制:
1. 基于开源的`UnQLite`数据库, 依赖于数据库;
2. 另外一种是基于`MTD CONFIG` (目前仅用于nor flash);
3. 最后一种基于`file`文件;
> `kvdb`一般接口说明: [frameworks/utils/include/kvdb.h](include/kvdb.h)
#### 2.2 `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_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
log模块本身是一个wrapper层,底层将Vela log系统进行了封装,封装成的API是和Android当中的log API一致, 当我们将Android应用或者框架移植到Vela当中, 不需要再提供自己的log对接,直接使用当前模块就可以了.
以下是log模块的结构:
```log
android log api
|
\|/
log wrapper
|
\|/
vela log impl
```
### 4. trace
这个模块当中包含的主要是用于用户空间程序的打点工具. 我们可以通过在用户程序当中手动插桩来实现打点分析.
trace当中提供的atrace工具主要是配合Vela系统提供的打点工具来使用的.
## 使用指南
### 1. gdbus
1. 打开`CONFIG_LIB_DBUS`选项
2. 实例化
gdbus为接口模块, 需要调用者实例化, 并在调用gdbus接口时, 传入实例化对象.
调用者需要创建一个结构体, 成员至少有`gdbus Connection`和`client`实例对象, 类似如下:
```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));
//创建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)
{
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);
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;
}
```
#### 2.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>到数据库
下面是具体的使用示例:
```log
nsh> setprop name peter #添加名为name值为peter的键值对 掉电消失
nsh> setprop persist.name1 peter1 #添加名为name1值为peter1的键值对 掉电不消失
nsh> getprop #查看所有键值对
name: peter
nsh> setprop name #删除名为name的键值对
nsh> getprop name
```
### 3. log
1. 打开`CONFIG_ANDROID_LIBBASE`
2. 然后我们可以在程序当中直接使用标准的android log api来收集打印日志.
```cpp
#include <log/log.h>
#define LOG_TAG "MyAppTag"
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;
}
```
### 4. trace
1. 打开`CONFIG_SCHED_INSTRUMENTATION_DUMP`和`CONFIG_ATRACE`选项
2. 在程序当中需要跟踪的地方添加上打点信息:
```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;
}
```
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
```
另外就是 atrace 的输出结果也是可以直接使用 [perfetto](https://ui.perfetto.dev/) 工具以可视化的形式来查看 trace 的时序图的.

437
include/android/log.h Normal file
View File

@ -0,0 +1,437 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.
*/
#pragma once
/**
* @addtogroup Logging
* @{
*/
/**
* \file
*
* Support routines to send messages to the Android log buffer,
* which can later be accessed through the `logcat` utility.
*
* Each log message must have
* - a priority
* - a log tag
* - some text
*
* The tag normally corresponds to the component that emits the log message,
* and should be reasonably small.
*
* Log message text may be truncated to less than an implementation-specific
* limit (1023 bytes).
*
* Note that a newline character ("\n") will be appended automatically to your
* log message, if not already there. It is not possible to send several
* messages and have them appear on a single line in logcat.
*
* Please use logging in moderation:
*
* - Sending log messages eats CPU and slow down your application and the
* system.
*
* - The circular log buffer is pretty small, so sending many messages
* will hide other important log messages.
*
* - In release builds, only send log messages to account for exceptional
* conditions.
*/
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
#define __INTRODUCED_IN(x)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/**
* @brief Android log priority values, in increasing order of priority.
*
* In Vela, we could using the CONFIG_ALOG to control the default log filter level
*/
typedef enum android_LogPriority {
/**
* @brief For internal use only.
*/
ANDROID_LOG_UNKNOWN = 0,
/**
* @brief The default priority, for internal use only.
* only for SetMinPriority()
*/
ANDROID_LOG_DEFAULT,
/**
* @brief Verbose logging. Should typically be disabled for a release apk.
*/
ANDROID_LOG_VERBOSE,
/**
* @brief Debug logging. Should typically be disabled for a release apk.
*/
ANDROID_LOG_DEBUG,
/**
* @brief Informational logging. Should typically be disabled for a release apk.
*/
ANDROID_LOG_INFO,
/**
* @brief Warning logging. For use with recoverable failures.
*/
ANDROID_LOG_WARN,
/**
* @brief Error logging. For use with unrecoverable failures.
*/
ANDROID_LOG_ERROR,
/**
* @brief Fatal logging. For use when aborting.
*/
ANDROID_LOG_FATAL,
/**
* @brief For internal use only.
* only for SetMinPriority(); must be last
*/
ANDROID_LOG_SILENT,
} android_LogPriority;
/**
* @brief Writes the constant string `text` to the log, with priority `prio` and tag
* `tag`.
* @param[in] prio the log filter level
* @param[in] tag the tag using to trace and filter log info
* @param[in] text the detailed log content to print out or record
* @return return 0 on success, non-zero on failure
*/
int __android_log_write(int prio, const char* tag, const char* text);
/**
* @brief Writes a formatted string to the log, with priority `prio` and tag `tag`.
* The details of formatting are the same as for
* [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*
* @param[in] prio the log filter level
* @param[in] tag the tag using to trace and filter log info
* @param[in] fmt the formatted string
* @return return 0 on success, non-zero on failure
*/
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
__attribute__((__format__(printf, 3, 4)));
/**
* @brief Equivalent to `__android_log_print`, but taking a `va_list`.
* (If `__android_log_print` is like `printf`, this is like `vprintf`.)
*
* @param[in] prio the log filter level
* @param[in] tag the tag using to trace and filter log info
* @param[in] fmt the formatted string
* @param[in] ap variadic list of all parameters
* @return return 0 on success, non-zero on failure
*/
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
__attribute__((__format__(printf, 3, 0)));
/**
* @brief Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
* stderr, before calling
* [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
*
* If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
* `Assertion failed: %s` is used with `cond` as the string argument.
* If both `fmt` and `cond` are null, a default string is provided.
*
* Most callers should use
* [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
* `&lt;assert.h&gt;` instead, or the `__assert` and `__assert2` functions
* provided by bionic if more control is needed. They support automatically
* including the source filename and line number more conveniently than this
* function.
*
* @param[in] cond the string representation of assertion condition
* @param[in] tag the tag using to trace and filter log info
* @param[in] fmt the formatted string
* @return return 0 on success, non-zero on failure
*/
void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...)
__attribute__((__noreturn__)) __attribute__((__format__(printf, 3, 4)));
/**
* @brief Identifies a specific log buffer for __android_log_buf_write()
* and __android_log_buf_print().
*/
typedef enum log_id {
LOG_ID_MIN = 0,
/**
* @brief The main log buffer. This is the only log buffer available to apps.
*/
LOG_ID_MAIN = 0,
/**
* @brief The radio log buffer.
*/
LOG_ID_RADIO = 1,
/**
* @brief The event log buffer.
*/
LOG_ID_EVENTS = 2,
/**
* @brief The system log buffer.
*/
LOG_ID_SYSTEM = 3,
/**
* @brief The crash log buffer.
*/
LOG_ID_CRASH = 4,
/**
* @brief The statistics log buffer.
*/
LOG_ID_STATS = 5,
/**
* @brief The security log buffer.
*/
LOG_ID_SECURITY = 6,
/**
* @brief The kernel log buffer.
*/
LOG_ID_KERNEL = 7,
LOG_ID_MAX,
/** Let the logging function choose the best log target. */
LOG_ID_DEFAULT = 0x7FFFFFFF
} log_id_t;
/**
* Writes the constant string `text` to the log buffer `id`,
* with priority `prio` and tag `tag`.
*
* Apps should use __android_log_write() instead.
*/
int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
/**
* Writes a formatted string to log buffer `id`,
* with priority `prio` and tag `tag`.
* The details of formatting are the same as for
* [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*
* Apps should use __android_log_print() instead.
*/
int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
__attribute__((__format__(printf, 4, 5)));
/**
* Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
* and sending log messages to user defined loggers specified in __android_log_set_logger().
*/
struct __android_log_message {
/** Must be set to sizeof(__android_log_message) and is used for versioning. */
size_t struct_size;
/** {@link log_id_t} values. */
int32_t buffer_id;
/** {@link android_LogPriority} values. */
int32_t priority;
/** The tag for the log message. */
const char* tag;
/** Optional file name, may be set to nullptr. */
const char* file;
/** Optional line number, ignore if file is nullptr. */
uint32_t line;
/** The log message itself. */
const char* message;
};
/**
* Prototype for the 'logger' function that is called for every log message.
*/
typedef void (*__android_logger_function)(const struct __android_log_message* log_message);
/**
* Prototype for the 'abort' function that is called when liblog will abort due to
* __android_log_assert() failures.
*/
typedef void (*__android_aborter_function)(const char* abort_message);
/**
* Writes the log message specified by log_message. log_message includes additional file name and
* line number information that a logger may use. log_message is versioned for backwards
* compatibility.
* This assumes that loggability has already been checked through __android_log_is_loggable().
* Higher level logging libraries, such as libbase, first check loggability, then format their
* buffers, then pass the message to liblog via this function, and therefore we do not want to
* duplicate the loggability check here.
*
* @param log_message the log message itself, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_write_log_message(struct __android_log_message* log_message) __INTRODUCED_IN(30);
/**
* Sets a user defined logger function. All log messages sent to liblog will be set to the
* function pointer specified by logger for processing. It is not expected that log messages are
* already terminated with a new line. This function should add new lines if required for line
* separation.
*
* @param logger the new function that will handle log messages.
*
* Available since API level 30.
*/
void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
/**
* Writes the log message to logd. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on a device.
*
* @param log_message the log message to write, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_logd_logger(const struct __android_log_message* log_message) __INTRODUCED_IN(30);
/**
* Writes the log message to stderr. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on host.
*
* @param log_message the log message to write, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_stderr_logger(const struct __android_log_message* log_message)
__INTRODUCED_IN(30);
/**
* Sets a user defined aborter function that is called for __android_log_assert() failures. This
* user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
* required to.
*
* @param aborter the new aborter function, see __android_aborter_function.
*
* Available since API level 30.
*/
void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
/**
* Calls the stored aborter function. This allows for other logging libraries to use the same
* aborter function by calling this function in liblog.
*
* @param abort_message an additional message supplied when aborting, for example this is used to
* call android_set_abort_message() in __android_log_default_aborter().
*
* Available since API level 30.
*/
void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
/**
* Sets android_set_abort_message() on device then aborts(). This is the default aborter.
*
* @param abort_message an additional message supplied when aborting. This functions calls
* android_set_abort_message() with its contents.
*
* Available since API level 30.
*/
void __android_log_default_aborter(const char* abort_message) __attribute__((noreturn))
__INTRODUCED_IN(30);
/**
* Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
* __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
* be printed. A non-zero result indicates yes, zero indicates false.
*
* If both a priority for a tag and a minimum priority are set by
* __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
* minimum priority needed to log. If only one is set, then that value is used to determine the
* minimum priority needed. If none are set, then default_priority is used.
*
* @param prio the priority to test, takes android_LogPriority values.
* @param tag the tag to test.
* @param default_prio the default priority to use if no properties or minimum priority are set.
* @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
*
* Available since API level 30.
*/
int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
/**
* Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
* __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
* be printed. A non-zero result indicates yes, zero indicates false.
*
* If both a priority for a tag and a minimum priority are set by
* __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
* minimum priority needed to log. If only one is set, then that value is used to determine the
* minimum priority needed. If none are set, then default_priority is used.
*
* @param prio the priority to test, takes android_LogPriority values.
* @param tag the tag to test.
* @param len the length of the tag.
* @param default_prio the default priority to use if no properties or minimum priority are set.
* @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
*
* Available since API level 30.
*/
int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
__INTRODUCED_IN(30);
/**
* Sets the minimum priority that will be logged for this process.
*
* @param priority the new minimum priority to set, takes android_LogPriority values.
* @return the previous set minimum priority as android_LogPriority values, or
* ANDROID_LOG_DEFAULT if none was set.
*
* Available since API level 30.
*/
int32_t __android_log_set_minimum_priority(int32_t priority) __INTRODUCED_IN(30);
/**
* Gets the minimum priority that will be logged for this process. If none has been set by a
* previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
*
* @return the current minimum priority as android_LogPriority values, or
* ANDROID_LOG_DEFAULT if none is set.
*
* Available since API level 30.
*/
int32_t __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
/**
* Sets the default tag if no tag is provided when writing a log message. Defaults to
* getprogname(). This truncates tag to the maximum log message size, though appropriate tags
* should be much smaller.
*
* @param tag the new log tag.
*
* Available since API level 30.
*/
void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
/* clang-format on */
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
/**
* @file android/set_abort_message.h
* @brief The android_set_abort_message() function.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* android_set_abort_message() sets the abort message that will be shown
* by [debuggerd](https://source.android.com/devices/tech/debug/native-crash).
* This is meant for use by libraries that deliberately abort so that they can
* provide an explanation. It is used within bionic to implement assert() and
* all FORTIFY/fdsan aborts.
*
* Available since API level 21.
*/
void android_set_abort_message(const char* __msg);
#ifdef __cplusplus
}
#endif

145
include/cutils/properties.h Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <sys/system_properties.h>
#ifdef __cplusplus
extern "C" {
#endif
//
// Deprecated.
//
// See <android-base/properties.h> for better API.
//
#define PROPERTY_KEY_MAX PROP_NAME_MAX
#define PROPERTY_VALUE_MAX PROP_VALUE_MAX
/* property_get: returns the length of the value which will never be
** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
** (the length does not include the terminating zero).
**
** If the property read fails or returns an empty value, the default
** value is used (if nonnull).
*/
int property_get(const char* key, char* value, const char* default_value);
/* property_get_bool: returns the value of key coerced into a
** boolean. If the property is not set, then the default value is returned.
**
* The following is considered to be true (1):
** "1", "true", "y", "yes", "on"
**
** The following is considered to be false (0):
** "0", "false", "n", "no", "off"
**
** The conversion is whitespace-sensitive (e.g. " off" will not be false).
**
** 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);
/* 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.
**
** The numeric conversion is identical to strtoimax with the base inferred:
** - All digits up to the first non-digit characters are read
** - The longest consecutive prefix of digits is converted to a long
**
** Valid strings of digits are:
** - An optional sign character + or -
** - An optional prefix indicating the base (otherwise base 10 is assumed)
** -- 0 prefix is octal
** -- 0x / 0X prefix is hex
**
** Leading/trailing whitespace is ignored. Overflow/underflow will cause
** numeric conversion to fail.
**
** 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);
/* 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.
**
** The numeric conversion is identical to strtoimax with the base inferred:
** - All digits up to the first non-digit characters are read
** - The longest consecutive prefix of digits is converted to a long
**
** Valid strings of digits are:
** - An optional sign character + or -
** - An optional prefix indicating the base (otherwise base 10 is assumed)
** -- 0 prefix is octal
** -- 0x / 0X prefix is hex
**
** Leading/trailing whitespace is ignored. Overflow/underflow will cause
** numeric conversion to fail.
**
** 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);
/* property_set: returns 0 on success, < 0 on failure
*/
int property_set(const char* key, const char* value);
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"
#if defined(__clang__)
/* Some projects use -Weverything; diagnose_if is clang-specific. */
#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);
#pragma clang diagnostic pop
#else /* defined(__clang__) */
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)
{
size_t bos = __bos(value);
if (bos < PROPERTY_VALUE_MAX) {
__property_get_too_small_error();
}
return __property_get_real(key, value, default_value);
}
#endif /* defined(__clang__) */
#undef __property_get_err_str
#endif /* defined(__BIONIC_FORTIFY) */
#ifdef __cplusplus
}
#endif

300
include/cutils/trace.h Normal file
View File

@ -0,0 +1,300 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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 _LIBS_CUTILS_TRACE_H
#define _LIBS_CUTILS_TRACE_H
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/**
* Define ATRACE_TAG before including this header to filter tracing by one of the tags below.
* Use ATRACE_TAG_ALWAYS for always-on tracing (debug only, as it incurs performance cost).
* ATRACE_TAG_NEVER or undefined disables tracing.
*
* For hardware modules, combine ATRACE_TAG_HAL with relevant tags, e.g., for camera:
* #define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
*
* Sync with frameworks/base/core/java/android/os/Trace.java.
*/
#define ATRACE_TAG_NEVER 0
#define ATRACE_TAG_ALWAYS (1<<0)
#define ATRACE_TAG_GRAPHICS (1<<1)
#define ATRACE_TAG_INPUT (1<<2)
#define ATRACE_TAG_VIEW (1<<3)
#define ATRACE_TAG_WEBVIEW (1<<4)
#define ATRACE_TAG_WINDOW_MANAGER (1<<5)
#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6)
#define ATRACE_TAG_SYNC_MANAGER (1<<7)
#define ATRACE_TAG_AUDIO (1<<8)
#define ATRACE_TAG_VIDEO (1<<9)
#define ATRACE_TAG_CAMERA (1<<10)
#define ATRACE_TAG_HAL (1<<11)
#define ATRACE_TAG_APP (1<<12)
#define ATRACE_TAG_RESOURCES (1<<13)
#define ATRACE_TAG_DALVIK (1<<14)
#define ATRACE_TAG_RS (1<<15)
#define ATRACE_TAG_BIONIC (1<<16)
#define ATRACE_TAG_POWER (1<<17)
#define ATRACE_TAG_PACKAGE_MANAGER (1<<18)
#define ATRACE_TAG_SYSTEM_SERVER (1<<19)
#define ATRACE_TAG_DATABASE (1<<20)
#define ATRACE_TAG_NETWORK (1<<21)
#define ATRACE_TAG_ADB (1<<22)
#define ATRACE_TAG_VIBRATOR (1<<23)
#define ATRACE_TAG_AIDL (1<<24)
#define ATRACE_TAG_NNAPI (1<<25)
#define ATRACE_TAG_RRO (1<<26)
#define ATRACE_TAG_THERMAL (1 << 27)
#define ATRACE_TAG_LAST ATRACE_TAG_THERMAL
/* Reserved for initialization. */
#define ATRACE_TAG_NOT_READY (1ULL<<63)
#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
#ifndef ATRACE_TAG
#define ATRACE_TAG ATRACE_TAG_NEVER
#elif ATRACE_TAG_VALID_MASK < ATRACE_TAG
#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
#endif
/**
* Opens trace file and reads initial tags from the system property.
* This is automatically called when the first trace function is used.
*/
void atrace_setup(void);
/**
* Updates `atrace_enabled_tags` from the system property `debug.atrace.tags.enableflags`.
*/
void atrace_update_tags(void);
/**
* Enables or disables tracing for the current process (to prevent tracing in Zygote).
*/
void atrace_set_tracing_enabled(bool enabled);
/**
* Set of enabled trace tags, initialized to ATRACE_TAG_NOT_READY. Zero indicates failure.
*/
extern uint64_t atrace_enabled_tags;
/**
* Kernel trace buffer handle, initialized to -1. A valid fd indicates setup success.
*/
extern int atrace_marker_fd;
/**
* Initializes tracing by opening the trace_marker file (optional, runs automatically).
*/
#define ATRACE_INIT() atrace_init()
#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
void atrace_init(void);
uint64_t atrace_get_enabled_tags(void);
/**
* Checks if a given trace tag is enabled, useful for expensive trace calculations.
* Returns nonzero if enabled, zero otherwise.
*/
#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG)
static inline uint64_t atrace_is_tag_enabled(uint64_t tag)
{
return atrace_get_enabled_tags() & tag;
}
/**
* Starts a tracing context, typically used for function timing.
* @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)) {
atrace_begin_body(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)) {
atrace_end_body();
}
}
/**
* Starts an asynchronous tracing event. Unlike ATRACE_BEGIN/END, async events don't require nesting.
* @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)
{
if (atrace_is_tag_enabled(tag)) {
atrace_async_begin_body(name, cookie);
}
}
/**
* Ends an asynchronous tracing event, matching a previous ATRACE_ASYNC_BEGIN.
* @param name: Event 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)) {
atrace_async_end_body(name, cookie);
}
}
/**
* Starts an asynchronous event with a trace track.
* @param track_name: Track name where this async event is recorded.
* @param name: Event name.
* @param cookie: Unique event identifier.
*/
#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);
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)) {
atrace_async_for_track_begin_body(track_name, name, cookie);
}
}
/**
* @brief To indicate the beginning of async tracing action with trace info
*
* Trace the end of an asynchronous event.
* This should correspond to a previous ATRACE_ASYNC_FOR_TRACK_BEGIN.
* @param[in] trace_name the track name is the name of the row where this
* async event should be recorded. The track name,
* name, and cookie used to begin an event must be
* used to end it.
* @param[in] name the name to describes the event
* @param[in] cookie using to provides a unique identifier for distinguishing
* simultaneous events. The name and cookie used to begin an
* event must be used to end it.
*/
#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)) {
atrace_async_for_track_end_body(track_name, name, cookie);
}
}
/**
* @brief To indicate trace an instantaneous context
* An "instant" is an event with no defined duration. Visually is displayed like a single marker
* in the timeline (rather than a span, in the case of begin/end events).
*
* By default, instant events are added into a dedicated track that has the same name of the event.
* Use atrace_instant_for_track to put different instant events into the same timeline track/row.
*
* @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)) {
atrace_instant_body(name);
}
}
/**
* @brief To indicate trace an instantaneous context with track specified
*
* An "instant" is an event with no defined duration. Visually is displayed like a single marker
* in the timeline (rather than a span, in the case of begin/end events).
*
* @param[in] name the name used to identify the context.
* @param[in] track_name is the name of the row where the event should be recorded.
*/
#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)) {
atrace_instant_for_track_body(track_name, name);
}
}
/**
* @brief To indicate trace an integer counter value
*
* @param[in] name is used to identify the counter.
* @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)) {
atrace_int_body(name, value);
}
}
/**
* @brief To indicate trace an 64-bit integer counter value
*
* @param[in] name is used to identify the counter.
* @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)) {
atrace_int64_body(name, value);
}
}
/* clang-format on */
#ifdef __cplusplus
}
#endif
#endif // _LIBS_CUTILS_TRACE_H

203
include/kvdb.h Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright (C) 2020 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.
*/
#ifndef __KVDB_H
#define __KVDB_H
#include <cutils/properties.h>
#include <sys/types.h>
#define PROP_MSG_MAX (3 + PROP_NAME_MAX + PROP_VALUE_MAX) /* +3 = +1(opcode) +2(len) */
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @brief Store Key-Values to database.
* @param[in] key entry key string
* @param[in] value entry value string
* @note Key starting with "persist." will be stored permanently after commit,
* others will be lost after reboot.
* @return On success returns 0, -errno otherwise.
*/
int property_set_oneway(const char* key, const char* value);
/**
* @brief Delete a KV pair by key.
* @param[in] key entry key string
* @return On success returns 0, -errno otherwise.
*/
int property_delete(const char* key);
/**
* @brief Actively commit all property changes.
* @return On success returns 0, -errno otherwise.
*/
int property_commit(void);
/**
* @brief load default property value.
* @return On success returns 0, -errno otherwise.
*/
int property_load(const char* path);
/**
* @brief Exit the kvdb service.
* @return On success returns 0, -errno otherwise.
*/
int property_exit(void);
/**
* @brief Wait the monitored key until its value updated or key deleted
* @param[in] key the monitored key string, support fnmatch pattern
* @param[in] the length of the newvalue
* @param[in] timeout the wait timeout time (in milliseconds)
* @param[out] newkey pointer to a string buffer to receive the key of
* the updated/deleted value
* @param[out] newvalue pointer to a string buffer to receive the updated
* value or deleted value
* @return On success returns the length of the value.
*/
ssize_t property_wait(const char* key, char* newkey, void* newvalue, size_t val_len, int timeout);
/**
* @brief Open a key monitor channel
* @param[in] key the monitored key string, support fnmatch pattern
* @return On success returns a file descriptor, -errno otherwise.
*/
int property_monitor_open(const char* key);
/**
* @brief Read the monitored key and value
* @param[in] fd file descriptor returned by property_monitor_open()
* @param[in] the length of the newvalue
* @param[out] newkey pointer to a string buffer to receive the key of
* the updated/deleted value
* @param[out] newvalue pointer to a string buffer to receive the updated
* value or deleted value
* @return On success returns the length of the value.
*/
ssize_t property_monitor_read(int fd, char* newkey, void* newvalue, size_t val_len);
/**
* @brief Close a key monitor channel
* @param[in] fd file descriptor returned by property_monitor_open()
* @return On success returns 0, -errno otherwise.
*/
int property_monitor_close(int fd);
/**
* @brief Saves a boolean to database.
* @param[in] key entry key string
* @param[in] value entry boolean value
* @return On success returns 0, -errno otherwise.
*/
int property_set_bool(const char* key, int8_t value);
int property_set_bool_oneway(const char* key, int8_t value);
/**
* @brief Saves an 32-bit integer to database.
* @param[in] key entry key string
* @param[in] value entry value
* @return On success returns 0, -errno otherwise.
*/
int property_set_int32(const char* key, int32_t value);
int property_set_int32_oneway(const char* key, int32_t value);
/**
* @brief Saves an 64-bit integer to database.
* @param[in] key entry key string
* @param[in] value entry value
* @return On success returns 0, -errno otherwise.
*/
int property_set_int64(const char* key, int64_t value);
int property_set_int64_oneway(const char* key, int64_t value);
/**
* @brief Saves a binary buffer to database.
* @param[in] key entry key string
* @param[in] value buffer value
* @param[in] size entry size
* @return On success returns 0, -errno otherwise.
*/
int property_set_buffer(const char* key, const void* value, size_t size);
int property_set_buffer_oneway(const char* key, const void* value, size_t size);
/**
* @brief Retrieve a Key-Value from database and interpret as binary buffer.
* @param[in] key entry key string
* @param[in] value buffer value
* @param[in] size buffer size
* @return On success returns the array length, -errno otherwise.
*/
ssize_t property_get_buffer(const char* key, void* value, size_t size);
/**
* @brief Saves a the specified length buffer to database.
* @param[in] key entry key string
* @param[in] value buffer value
* @param[in] value buffer size
* @return On success returns the array length, -errno otherwise.
*/
int property_set_binary(const char* key, const void* value, size_t val_len, bool oneway);
ssize_t property_get_binary(const char* key, void* value, size_t val_len);
/**
* @List all KVs in every database and calls callback function.
* @param[in] callback function
* @param[in] cookie data to pass to callback function
* @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
#endif

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
struct EventTagMap;
typedef struct EventTagMap EventTagMap;
/*
* Open the specified file as an event log tag map.
*
* Returns NULL on failure.
*/
EventTagMap* android_openEventTagMap(const char* fileName);
/*
* Close the map.
*/
void android_closeEventTagMap(EventTagMap* map);
/*
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len,
unsigned int tag);
/*
* Look up a format by index. Returns the format string & string length,
* or NULL if not found. Returned string is not guaranteed to be nul terminated.
*/
const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len,
unsigned int tag);
#ifdef __cplusplus
}
#endif

151
include/log/log.h Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright (C) 2005-2014 The Android Open Source Project
*
* 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.
*/
#pragma once
/* Too many in the ecosystem assume these are included */
#if !defined(_WIN32)
#include <pthread.h>
#endif
#include <stdint.h> /* uint16_t, int32_t */
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <android/log.h>
#include <log/log_id.h>
#include <log/log_main.h>
#include <log/log_radio.h>
#include <log/log_safetynet.h>
#include <log/log_system.h>
#include <log/log_time.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* LOG_TAG is the local tag used for the following simplified
* logging macros. You can change this preprocessor definition
* before using the other macros to change the tag.
*/
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
/*
* Normally we strip the effects of ALOGV (VERBOSE messages),
* LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
* release builds be defining NDEBUG. You can modify this (for
* example with "#define LOG_NDEBUG 0" at the top of your source
* file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/*
* The maximum size of the log entry payload that can be
* written to the logger. An attempt to write more than
* this amount will result in a truncated log entry.
*/
#define LOGGER_ENTRY_MAX_PAYLOAD 4068
/*
* Event logging.
*/
/*
* The following should not be used directly.
*/
int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
int __android_log_btwrite(int32_t tag, char type, const void* payload,
size_t len);
int __android_log_bswrite(int32_t tag, const char* payload);
int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len);
#define android_bWriteLog(tag, payload, len) \
__android_log_bwrite(tag, payload, len)
#define android_btWriteLog(tag, type, payload, len) \
__android_log_btwrite(tag, type, payload, len)
/*
* Event log entry types.
*/
typedef enum {
/* Special markers for android_log_list_element type */
EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
EVENT_TYPE_UNKNOWN = '?', /* protocol error */
/* must match with declaration in java/android/android/util/EventLog.java */
EVENT_TYPE_INT = 0, /* int32_t */
EVENT_TYPE_LONG = 1, /* int64_t */
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
EVENT_TYPE_FLOAT = 4,
} AndroidEventLogType;
#ifndef LOG_EVENT_INT
#define LOG_EVENT_INT(_tag, _value) \
{ \
int intBuf = _value; \
(void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
}
#endif
#ifndef LOG_EVENT_LONG
#define LOG_EVENT_LONG(_tag, _value) \
{ \
long long longBuf = _value; \
(void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
}
#endif
#ifndef LOG_EVENT_FLOAT
#define LOG_EVENT_FLOAT(_tag, _value) \
{ \
float floatBuf = _value; \
(void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
sizeof(floatBuf)); \
}
#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
(void)__android_log_bswrite(_tag, _value);
#endif
/* --------------------------------------------------------------------- */
/*
* Release any logger resources (a new log write will immediately re-acquire)
*
* This is specifically meant to be used by Zygote to close open file descriptors after fork()
* and before specialization. O_CLOEXEC is used on file descriptors, so they will be closed upon
* exec() in normal use cases.
*
* Note that this is not safe to call from a multi-threaded program.
*/
void __android_log_close(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,278 @@
/*
* Copyright (C) 2005-2016 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <errno.h>
#include <stdint.h>
#ifdef __cplusplus
#include <string>
#endif
#include <log/log.h>
#ifdef __cplusplus
extern "C" {
#endif
/* For manipulating lists of events. */
#define ANDROID_MAX_LIST_NEST_DEPTH 8
/*
* The opaque context used to manipulate lists of events.
*/
typedef struct android_log_context_internal* android_log_context;
/*
* Elements returned when reading a list of events.
*/
typedef struct {
AndroidEventLogType type;
uint16_t complete;
uint16_t len;
union {
int32_t int32;
int64_t int64;
char* string;
float float32;
} data;
} android_log_list_element;
/*
* Creates a context associated with an event tag to write elements to
* the list of events.
*/
android_log_context create_android_logger(uint32_t tag);
/* All lists must be braced by a begin and end call */
/*
* NB: If the first level braces are missing when specifying multiple
* elements, we will manufacturer a list to embrace it for your API
* convenience. For a single element, it will remain solitary.
*/
int android_log_write_list_begin(android_log_context ctx);
int android_log_write_list_end(android_log_context ctx);
int android_log_write_int32(android_log_context ctx, int32_t value);
int android_log_write_int64(android_log_context ctx, int64_t value);
int android_log_write_string8(android_log_context ctx, const char* value);
int android_log_write_string8_len(android_log_context ctx, const char* value,
size_t maxlen);
int android_log_write_float32(android_log_context ctx, float value);
/* Submit the composed list context to the specified logger id */
/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
int android_log_write_list(android_log_context ctx, log_id_t id);
/*
* Creates a context from a raw buffer representing a list of events to be read.
*/
android_log_context create_android_log_parser(const char* msg, size_t len);
android_log_list_element android_log_read_next(android_log_context ctx);
android_log_list_element android_log_peek_next(android_log_context ctx);
/* Reset writer context */
int android_log_reset(android_log_context ctx);
/* Reset reader context */
int android_log_parser_reset(android_log_context ctx,
const char* msg, size_t len);
/* Finished with reader or writer context */
int android_log_destroy(android_log_context* ctx);
#ifdef __cplusplus
/* android_log_list C++ helpers */
extern "C++" {
class android_log_event_list {
private:
android_log_context ctx;
int ret;
android_log_event_list(const android_log_event_list&) = delete;
void operator=(const android_log_event_list&) = delete;
public:
explicit android_log_event_list(int tag) : ret(0) {
ctx = create_android_logger(static_cast<uint32_t>(tag));
}
~android_log_event_list() {
android_log_destroy(&ctx);
}
int close() {
int retval = android_log_destroy(&ctx);
if (retval < 0) ret = retval;
return retval;
}
/* To allow above C calls to use this class as parameter */
operator android_log_context() const {
return ctx;
}
/* return errors or transmit status */
int status() const {
return ret;
}
int begin() {
int retval = android_log_write_list_begin(ctx);
if (retval < 0) ret = retval;
return ret;
}
int end() {
int retval = android_log_write_list_end(ctx);
if (retval < 0) ret = retval;
return ret;
}
android_log_event_list& operator<<(int32_t value) {
int retval = android_log_write_int32(ctx, value);
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(uint32_t value) {
int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(bool value) {
int retval = android_log_write_int32(ctx, value ? 1 : 0);
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(int64_t value) {
int retval = android_log_write_int64(ctx, value);
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(uint64_t value) {
int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(const char* value) {
int retval = android_log_write_string8(ctx, value);
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(const std::string& value) {
int retval =
android_log_write_string8_len(ctx, value.data(), value.length());
if (retval < 0) ret = retval;
return *this;
}
android_log_event_list& operator<<(float value) {
int retval = android_log_write_float32(ctx, value);
if (retval < 0) ret = retval;
return *this;
}
int write(log_id_t id = LOG_ID_EVENTS) {
/* facilitate -EBUSY retry */
if ((ret == -EBUSY) || (ret > 0)) ret = 0;
int retval = android_log_write_list(ctx, id);
/* existing errors trump transmission errors */
if (!ret) ret = retval;
return ret;
}
int operator<<(log_id_t id) {
write(id);
android_log_destroy(&ctx);
return ret;
}
/*
* Append<Type> methods removes any integer promotion
* confusion, and adds access to string with length.
* Append methods are also added for all types for
* convenience.
*/
bool AppendInt(int32_t value) {
int retval = android_log_write_int32(ctx, value);
if (retval < 0) ret = retval;
return ret >= 0;
}
bool AppendLong(int64_t value) {
int retval = android_log_write_int64(ctx, value);
if (retval < 0) ret = retval;
return ret >= 0;
}
bool AppendString(const char* value) {
int retval = android_log_write_string8(ctx, value);
if (retval < 0) ret = retval;
return ret >= 0;
}
bool AppendString(const char* value, size_t len) {
int retval = android_log_write_string8_len(ctx, value, len);
if (retval < 0) ret = retval;
return ret >= 0;
}
bool AppendString(const std::string& value) {
int retval =
android_log_write_string8_len(ctx, value.data(), value.length());
if (retval < 0) ret = retval;
return ret;
}
bool Append(const std::string& value) {
int retval =
android_log_write_string8_len(ctx, value.data(), value.length());
if (retval < 0) ret = retval;
return ret;
}
bool AppendFloat(float value) {
int retval = android_log_write_float32(ctx, value);
if (retval < 0) ret = retval;
return ret >= 0;
}
template <typename Tvalue>
bool Append(Tvalue value) {
*this << value;
return ret >= 0;
}
bool Append(const char* value, size_t len) {
int retval = android_log_write_string8_len(ctx, value, len);
if (retval < 0) ret = retval;
return ret >= 0;
}
};
}
#endif
#ifdef __cplusplus
}
#endif

33
include/log/log_id.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <android/log.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* log_id_t helpers
*/
log_id_t android_name_to_log_id(const char* logName);
const char* android_log_id_to_name(log_id_t log_id);
#ifdef __cplusplus
}
#endif

422
include/log/log_main.h Normal file
View File

@ -0,0 +1,422 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <sys/types.h>
#include <android/log.h>
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/*
* Normally we strip the effects of ALOGV (VERBOSE messages),
* LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
* release builds be defining NDEBUG. You can modify this (for
* example with "#define LOG_NDEBUG 0" at the top of your source
* file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
#ifndef CONFIG_ALOG
#define CONFIG_ALOG_LEVEL -1
#endif
/* --------------------------------------------------------------------- */
/*
* This file uses ", ## __VA_ARGS__" zero-argument token pasting to
* work around issues with debug-only syntax errors in assertions
* that are missing format strings. See commit
* 19299904343daf191267564fe32e6cd5c165cd42
*/
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
/*
* Use __VA_ARGS__ if running a static analyzer,
* to avoid warnings of unused variables in __VA_ARGS__.
* Use constexpr function in C++ mode, so these macros can be used
* in other constexpr functions without warning.
*/
#ifdef __clang_analyzer__
#ifdef __cplusplus
extern "C++" {
template <typename... Ts>
constexpr int __fake_use_va_args(Ts...)
{
return 0;
}
}
#else
extern int __fake_use_va_args(int, ...);
#endif /* __cplusplus */
#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
#else
#define __FAKE_USE_VA_ARGS(...) ((void)(0))
#endif /* __clang_analyzer__ */
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
#define android_writeLog(prio, tag, text) __android_log_write(prio, tag, text)
#define android_printLog(prio, tag, ...) \
__android_log_print(prio, tag, __VA_ARGS__)
#define android_vprintLog(prio, cond, tag, ...) \
__android_log_vprint(prio, tag, __VA_ARGS__)
/*
* Log macro that allows you to specify a number for the priority.
*/
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to pass in a varargs ("args" is a va_list).
*/
#ifndef LOG_PRI_VA
#define LOG_PRI_VA(priority, tag, fmt, args) \
android_vprintLog(priority, NULL, tag, fmt, args)
#endif
/* --------------------------------------------------------------------- */
/* XXX Macros to work around syntax errors in places where format string
* arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
* (happens only in debug builds).
*/
/* Returns 2nd arg. Used to substitute default value if caller's vararg list
* is empty.
*/
#define __android_second(dummy, second, ...) second
/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
* returns nothing.
*/
#define __android_rest(first, ...) , ##__VA_ARGS__
#define android_printAssert(cond, tag, ...) \
__android_log_assert(cond, tag, \
__android_second(0, ##__VA_ARGS__, NULL) \
__android_rest(__VA_ARGS__))
/*
* Log a fatal error. If the given condition fails, this stops program
* execution like a normal assertion, but also generating the given message.
* It is NOT stripped from release builds. Note that the condition test
* is -inverted- from the normal assert() semantics.
*/
#ifndef LOG_ALWAYS_FATAL_IF
#if !defined(CONFIG_ALOG_LEVEL) || CONFIG_ALOG_LEVEL >= 0
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
((__predict_false(cond)) ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), \
((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__))) \
: ((void)0))
#else
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
((__predict_false(cond)) ? (__FAKE_USE_VA_ARGS(__VA_ARGS__)) : ((void)0))
#endif
#endif
#ifndef LOG_ALWAYS_FATAL
#if !defined(CONFIG_ALOG_LEVEL) || CONFIG_ALOG_LEVEL >= 0
#define LOG_ALWAYS_FATAL(...) \
(((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
#else
#define LOG_ALWAYS_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#endif
#endif
/*
* Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
* are stripped out of release builds.
*/
#if LOG_NDEBUG && !defined(CONFIG_ALOG_LEVEL) || defined(CONFIG_ALOG_LEVEL) && CONFIG_ALOG_LEVEL < 1
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
#endif
#else
#ifndef LOG_FATAL_IF
#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
#endif
#ifndef LOG_FATAL
#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
#endif
#endif
/*
* Assertion that generates a log message when the assertion fails.
* Stripped out of release builds. Uses the current LOG_TAG.
*/
#ifndef ALOG_ASSERT
#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
#endif
/* --------------------------------------------------------------------- */
/*
* C/C++ logging functions. See the logging documentation for API details.
*
* We'd like these to be available from C code (in case we import some from
* somewhere), so this has a C interface.
*
* The output will be correct when the log file is shared between multiple
* threads and/or multiple processes so long as the operating system
* supports O_APPEND. These calls have mutex-protected data structures
* and so are NOT reentrant. Do not use LOG in a signal handler.
*/
/* --------------------------------------------------------------------- */
/**
* @brief Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef ALOGV
#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGV_IF
#define ALOGV_IF(cond, ...) \
((__predict_false(cond)) \
? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
: ((void)0))
#endif
/**
* @brief Simplified macro to send a debug log message using the current LOG_TAG.
*/
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGD_IF
#define ALOGD_IF(cond, ...) \
((__predict_false(cond)) \
? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
: ((void)0))
#endif
/**
* @brief Simplified macro to send an info log message using the current LOG_TAG.
*/
#ifndef ALOGI
#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGI_IF
#define ALOGI_IF(cond, ...) \
((__predict_false(cond)) \
? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
: ((void)0))
#endif
/**
* @brief Simplified macro to send a warning log message using the current LOG_TAG.
*/
#ifndef ALOGW
#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGW_IF
#define ALOGW_IF(cond, ...) \
((__predict_false(cond)) \
? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
: ((void)0))
#endif
/**
* @brief Simplified macro to send an error log message using the current LOG_TAG.
*/
#ifndef ALOGE
#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#endif
#ifndef ALOGE_IF
#define ALOGE_IF(cond, ...) \
((__predict_false(cond)) \
? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
: ((void)0))
#endif
/* --------------------------------------------------------------------- */
/**
* @brief Conditional based on whether the current LOG_TAG is enabled at
* verbose priority.
*/
#ifndef IF_ALOGV
#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
#endif
/**
* @brief Conditional based on whether the current LOG_TAG is enabled at
* debug priority.
*/
#ifndef IF_ALOGD
#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
#endif
/**
* @brief Conditional based on whether the current LOG_TAG is enabled at
* info priority.
*/
#ifndef IF_ALOGI
#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
#endif
/**
* @brief Conditional based on whether the current LOG_TAG is enabled at
* warn priority.
*/
#ifndef IF_ALOGW
#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
#endif
/**
* @brief Conditional based on whether the current LOG_TAG is enabled at
* error priority.
*/
#ifndef IF_ALOGE
#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
#endif
/* --------------------------------------------------------------------- */
/*
* Basic log message macro.
*
* Example:
* ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
*
* The second argument may be NULL or "" to indicate the "global" tag.
*/
#ifndef ALOG
#ifndef CONFIG_ALOG_LEVEL
#define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#elif CONFIG_ALOG_LEVEL == 2
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_ERROR) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#elif CONFIG_ALOG_LEVEL == 3
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_WARN) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#elif CONFIG_ALOG_LEVEL == 4
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_INFO) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#elif CONFIG_ALOG_LEVEL == 5
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_DEBUG) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#elif CONFIG_ALOG_LEVEL == 6
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_VERBOSE) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#else
#define ALOG(priority, tag, ...) \
((ANDROID_##priority >= ANDROID_LOG_FATAL) ? LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) : 0)
#endif
#endif
/*
* Conditional given a desired logging priority and tag.
*/
#ifndef IF_ALOG
#define IF_ALOG(priority, tag) if (android_testLog(ANDROID_##priority, tag))
#endif
/* --------------------------------------------------------------------- */
/*
* IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
* android_testLog will remain constant in its purpose as a wrapper
* for Android logging filter policy, and can be subject to
* change. It can be reused by the developers that override
* IF_ALOG as a convenient means to reimplement their policy
* over Android.
*/
/*
* Use the per-tag properties "log.tag.<tagname>" to generate a runtime
* result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
* ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
* any other value.
*/
int __android_log_is_loggable(int prio, const char* tag, int default_prio);
int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
#ifdef CONFIG_ALOG_LEVEL
#if CONFIG_ALOG_LEVEL == 1
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_FATAL) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#elif CONFIG_ALOG_LEVEL == 2
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_ERROR) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#elif CONFIG_ALOG_LEVEL == 3
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_WARN) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#elif CONFIG_ALOG_LEVEL == 4
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_INFO) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#elif CONFIG_ALOG_LEVEL == 5
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_DEBUG) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#elif CONFIG_ALOG_LEVEL == 6
#define android_testLog(prio, tag) \
((prio >= ANDROID_LOG_VERBOSE) ? (__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, prio) != 0) : 0)
#else
#define android_testLog(prio, tag) 0
#endif
#elif LOG_NDEBUG /* Production */
#define android_testLog(prio, tag) \
(__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, ANDROID_LOG_DEBUG) != 0)
#else
#define android_testLog(prio, tag) \
(__android_log_is_loggable_len(prio, tag, (tag) ? strlen(tag) : 0, ANDROID_LOG_VERBOSE) != 0)
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
/* clang-format off */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* Returns `1` if the device is debuggable */
int __android_log_is_debuggable();
#ifdef __cplusplus
}
#endif

138
include/log/log_radio.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <android/log.h>
/*
* Normally we strip the effects of ALOGV (VERBOSE messages),
* LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
* release builds be defining NDEBUG. You can modify this (for
* example with "#define LOG_NDEBUG 0" at the top of your source
* file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
/* --------------------------------------------------------------------- */
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
/*
* Simplified macro to send a verbose radio log message using current LOG_TAG.
*/
#ifndef RLOGV
#define __RLOGV(...) \
((void)__android_log_buf_print(LOG_ID_RADIO, \
ANDROID_LOG_VERBOSE, \
LOG_TAG, \
__VA_ARGS__))
#if LOG_NDEBUG
#define RLOGV(...)
#else
#define RLOGV(...) __RLOGV(__VA_ARGS__)
#endif
#endif
#ifndef RLOGV_IF
#if LOG_NDEBUG
#define RLOGV_IF(cond, ...) ((void)0)
#else
#define RLOGV_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
#endif
/* Simplified macro to send a debug radio log message using current LOG_TAG. */
#ifndef RLOGD
#if LOG_NDEBUG
#define RLOGD(...) ((void)0)
#else
#define RLOGD(...) \
((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
__VA_ARGS__))
#endif
#endif
#ifndef RLOGD_IF
#define RLOGD_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/* Simplified macro to send an info radio log message using current LOG_TAG. */
#ifndef RLOGI
#define RLOGI(...) \
((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef RLOGI_IF
#define RLOGI_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/* Simplified macro to send a warning radio log message using current LOG_TAG. */
#ifndef RLOGW
#define RLOGW(...) \
((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef RLOGW_IF
#define RLOGW_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/*
* Simplified macro to send an error radio log message using current LOG_TAG.
*/
#ifndef RLOGE
#define RLOGE(...) \
((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef RLOGE_IF
#define RLOGE_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif

129
include/log/log_read.h Normal file
View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stdint.h>
#include <sys/types.h>
#include <android/log.h>
#include <log/log_time.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
/*
* Native log reading interface section. See logcat for sample code.
*
* The preferred API is an exec of logcat. Likely uses of this interface
* are if native code suffers from exec or filtration being too costly,
* access to raw information, or parsing is an issue.
*/
struct logger_entry {
uint16_t len; /* length of the payload */
uint16_t hdr_size; /* sizeof(struct logger_entry) */
int32_t pid; /* generating process's pid */
uint32_t tid; /* generating process's tid */
uint32_t sec; /* seconds since Epoch */
uint32_t nsec; /* nanoseconds */
uint32_t lid; /* log id of the payload, bottom 4 bits currently */
uint32_t uid; /* generating process's uid */
};
/*
* The maximum size of a log entry which can be read.
* An attempt to read less than this amount may result
* in read() returning EINVAL.
*/
#define LOGGER_ENTRY_MAX_LEN (5 * 1024)
struct log_msg {
union {
unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
struct logger_entry entry;
} __attribute__((aligned(4)));
#ifdef __cplusplus
uint64_t nsec() const {
return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
}
log_id_t id() {
return static_cast<log_id_t>(entry.lid);
}
char* msg() {
unsigned short hdr_size = entry.hdr_size;
if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
return nullptr;
}
return reinterpret_cast<char*>(buf) + hdr_size;
}
unsigned int len() { return entry.hdr_size + entry.len; }
#endif
};
struct logger;
log_id_t android_logger_get_id(struct logger* logger);
/* Clears the given log buffer. */
int android_logger_clear(struct logger* logger);
/* Return the allotted size for the given log buffer. */
long android_logger_get_log_size(struct logger* logger);
/* Set the allotted size for the given log buffer. */
int android_logger_set_log_size(struct logger* logger, unsigned long size);
/* Return the actual, uncompressed size that can be read from the given log buffer. */
long android_logger_get_log_readable_size(struct logger* logger);
/* Return the actual, compressed size that the given log buffer is consuming. */
long android_logger_get_log_consumed_size(struct logger* logger);
/* Deprecated. Always returns '4' regardless of input. */
int android_logger_get_log_version(struct logger* logger);
struct logger_list;
ssize_t android_logger_get_statistics(struct logger_list* logger_list,
char* buf, size_t len);
ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
char* buf, size_t len);
int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len);
/* The below values are used for the `mode` argument of the below functions. */
/* Note that 0x00000003 were previously used and should be considered reserved. */
#define ANDROID_LOG_NONBLOCK 0x00000800
#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
#define ANDROID_LOG_PSTORE 0x80000000
struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
pid_t pid);
struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
pid_t pid);
void android_logger_list_free(struct logger_list* logger_list);
/* In the purest sense, the following two are orthogonal interfaces */
int android_logger_list_read(struct logger_list* logger_list,
struct log_msg* log_msg);
/* Multiple log_id_t opens */
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
/* Single log_id_t open */
struct logger_list* android_logger_list_open(log_id_t id, int mode,
unsigned int tail, pid_t pid);
#define android_logger_list_close android_logger_list_free
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define android_errorWriteLog(tag, subTag) \
__android_log_error_write(tag, subTag, -1, NULL, 0)
#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
__android_log_error_write(tag, subTag, uid, data, dataLen)
int __android_log_error_write(int tag, const char* subTag, int32_t uid,
const char* data, uint32_t dataLen);
#ifdef __cplusplus
}
#endif

138
include/log/log_system.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <android/log.h>
/*
* Normally we strip the effects of ALOGV (VERBOSE messages),
* LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
* release builds be defining NDEBUG. You can modify this (for
* example with "#define LOG_NDEBUG 0" at the top of your source
* file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
/*
* Simplified macro to send a verbose system log message using current LOG_TAG.
*/
#ifndef SLOGV
#define __SLOGV(...) \
((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
__VA_ARGS__))
#if LOG_NDEBUG
#define SLOGV(...) \
do { \
if (0) { \
__SLOGV(__VA_ARGS__); \
} \
} while (0)
#else
#define SLOGV(...) __SLOGV(__VA_ARGS__)
#endif
#endif
#ifndef SLOGV_IF
#if LOG_NDEBUG
#define SLOGV_IF(cond, ...) ((void)0)
#else
#define SLOGV_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
#endif
/*
* Simplified macro to send a debug system log message using current LOG_TAG.
*/
#ifndef SLOGD
#define SLOGD(...) \
((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef SLOGD_IF
#define SLOGD_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/*
* Simplified macro to send an info system log message using current LOG_TAG.
*/
#ifndef SLOGI
#define SLOGI(...) \
((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef SLOGI_IF
#define SLOGI_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/*
* Simplified macro to send a warning system log message using current LOG_TAG.
*/
#ifndef SLOGW
#define SLOGW(...) \
((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef SLOGW_IF
#define SLOGW_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif
/*
* Simplified macro to send an error system log message using current LOG_TAG.
*/
#ifndef SLOGE
#define SLOGE(...) \
((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
__VA_ARGS__))
#endif
#ifndef SLOGE_IF
#define SLOGE_IF(cond, ...) \
((__predict_false(cond)) \
? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, \
LOG_TAG, __VA_ARGS__)) \
: (void)0)
#endif

162
include/log/log_time.h Normal file
View File

@ -0,0 +1,162 @@
/*
* Copyright (C) 2005-2017 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stdint.h>
#include <time.h>
/* struct log_time is a wire-format variant of struct timespec */
#define NS_PER_SEC 1000000000ULL
#define US_PER_SEC 1000000ULL
#define MS_PER_SEC 1000ULL
#define LOG_TIME_SEC(t) ((t)->tv_sec)
/* next power of two after NS_PER_SEC */
#define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
#ifdef __cplusplus
extern "C" {
struct log_time {
public:
uint32_t tv_sec = 0; /* good to Feb 5 2106 */
uint32_t tv_nsec = 0;
static constexpr timespec EPOCH = {0, 0};
log_time() {}
explicit log_time(const timespec& T)
: tv_sec(static_cast<uint32_t>(T.tv_sec)), tv_nsec(static_cast<uint32_t>(T.tv_nsec)) {}
explicit log_time(uint32_t sec, uint32_t nsec = 0)
: tv_sec(sec), tv_nsec(nsec) {
}
#ifdef __linux__
explicit log_time(clockid_t id) {
timespec T;
clock_gettime(id, &T);
tv_sec = static_cast<uint32_t>(T.tv_sec);
tv_nsec = static_cast<uint32_t>(T.tv_nsec);
}
#endif
/* timespec */
bool operator==(const timespec& T) const {
return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
(tv_nsec == static_cast<uint32_t>(T.tv_nsec));
}
bool operator!=(const timespec& T) const {
return !(*this == T);
}
bool operator<(const timespec& T) const {
return (tv_sec < static_cast<uint32_t>(T.tv_sec)) ||
((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
(tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
}
bool operator>=(const timespec& T) const {
return !(*this < T);
}
bool operator>(const timespec& T) const {
return (tv_sec > static_cast<uint32_t>(T.tv_sec)) ||
((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
(tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
}
bool operator<=(const timespec& T) const {
return !(*this > T);
}
/* log_time */
bool operator==(const log_time& T) const {
return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
}
bool operator!=(const log_time& T) const {
return !(*this == T);
}
bool operator<(const log_time& T) const {
return (tv_sec < T.tv_sec) ||
((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
}
bool operator>=(const log_time& T) const {
return !(*this < T);
}
bool operator>(const log_time& T) const {
return (tv_sec > T.tv_sec) ||
((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
}
bool operator<=(const log_time& T) const {
return !(*this > T);
}
log_time operator-=(const log_time& T) {
// No concept of negative time, clamp to EPOCH
if (*this <= T) {
return *this = log_time(EPOCH);
}
if (this->tv_nsec < T.tv_nsec) {
--this->tv_sec;
this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
} else {
this->tv_nsec -= T.tv_nsec;
}
this->tv_sec -= T.tv_sec;
return *this;
}
log_time operator-(const log_time& T) const {
log_time local(*this);
return local -= T;
}
log_time operator+=(const log_time& T) {
this->tv_nsec += T.tv_nsec;
if (this->tv_nsec >= NS_PER_SEC) {
this->tv_nsec -= NS_PER_SEC;
++this->tv_sec;
}
this->tv_sec += T.tv_sec;
return *this;
}
log_time operator+(const log_time& T) const {
log_time local(*this);
return local += T;
}
uint64_t nsec() const {
return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
}
uint64_t usec() const {
return static_cast<uint64_t>(tv_sec) * US_PER_SEC +
tv_nsec / (NS_PER_SEC / US_PER_SEC);
}
uint64_t msec() const {
return static_cast<uint64_t>(tv_sec) * MS_PER_SEC +
tv_nsec / (NS_PER_SEC / MS_PER_SEC);
}
/* Add %#q for the fraction of a second to the standard library functions */
char* strptime(const char* s, const char* format);
} __attribute__((__packed__));
}
#else /* __cplusplus */
typedef struct log_time {
uint32_t tv_sec;
uint32_t tv_nsec;
} __attribute__((__packed__)) log_time;
#endif /* __cplusplus */

157
include/log/logprint.h Normal file
View File

@ -0,0 +1,157 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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.
*/
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <android/log.h>
#include <log/event_tag_map.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
/* Verbs */
FORMAT_OFF = 0,
FORMAT_BRIEF,
FORMAT_PROCESS,
FORMAT_TAG,
FORMAT_THREAD,
FORMAT_RAW,
FORMAT_TIME,
FORMAT_THREADTIME,
FORMAT_LONG,
/* Adverbs. The following are modifiers to above format verbs */
FORMAT_MODIFIER_COLOR, /* converts priority to color */
FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
FORMAT_MODIFIER_YEAR, /* Adds year to date */
FORMAT_MODIFIER_ZONE, /* Adds zone to date, + UTC */
FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
FORMAT_MODIFIER_UID, /* Adds uid */
FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
/* private, undocumented */
FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
typedef struct AndroidLogEntry_t {
time_t tv_sec;
long tv_nsec;
android_LogPriority priority;
int32_t uid;
int32_t pid;
int32_t tid;
const char* tag;
size_t tagLen;
size_t messageLen;
const char* message;
} AndroidLogEntry;
AndroidLogFormat* android_log_format_new();
void android_log_format_free(AndroidLogFormat* p_format);
/* currently returns 0 if format is a modifier, 1 if not */
int android_log_setPrintFormat(AndroidLogFormat* p_format,
AndroidLogPrintFormat format);
/**
* Returns FORMAT_OFF on invalid string
*/
AndroidLogPrintFormat android_log_formatFromString(const char* s);
/**
* filterExpression: a single filter expression
* eg "AT:d"
*
* returns 0 on success and -1 on invalid expression
*
* Assumes single threaded execution
*
*/
int android_log_addFilterRule(AndroidLogFormat* p_format,
const char* filterExpression);
/**
* filterString: a whitespace-separated set of filter expressions
* eg "AT:d *:i"
*
* returns 0 on success and -1 on invalid expression
*
* Assumes single threaded execution
*
*/
int android_log_addFilterString(AndroidLogFormat* p_format,
const char* filterString);
/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
android_LogPriority pri);
/**
* Splits a wire-format buffer into an AndroidLogEntry
* entry allocated by caller. Pointers will point directly into buf
*
* Returns 0 on success and -1 on invalid wire format (entry will be
* in unspecified state)
*/
int android_log_processLogBuffer(struct logger_entry* buf,
AndroidLogEntry* entry);
/**
* Like android_log_processLogBuffer, but for binary logs.
*
* If "map" is non-NULL, it will be used to convert the log tag number
* into a string.
*/
int android_log_processBinaryLogBuffer(struct logger_entry* buf,
AndroidLogEntry* entry,
const EventTagMap* map, char* messageBuf,
int messageBufLen);
/**
* Formats a log message into a buffer
*
* Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
* If return value != defaultBuffer, caller must call free()
* Returns NULL on malloc error
*/
char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
size_t defaultBufferSize,
const AndroidLogEntry* p_line,
size_t* p_outLength);
/**
* Formats a log message into a FILE*.
*/
size_t android_log_printLogLine(AndroidLogFormat* p_format, FILE* fp, const AndroidLogEntry* entry);
#ifdef __cplusplus
}
#endif

81
include/murmurhash.h Normal file
View File

@ -0,0 +1,81 @@
#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

@ -0,0 +1,151 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
/* This file is used to define the internal protocol for the Android Logger */
#pragma once
/* Android private interfaces */
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#ifdef __cplusplus
#include <string>
#endif
#include <log/log.h>
#include <log/log_event_list.h>
#define LOGGER_MAGIC 'l'
#if defined(__cplusplus)
extern "C" {
#endif
/* Header Structure to pstore */
typedef struct __attribute__((__packed__)) {
uint8_t magic;
uint16_t len;
uint16_t uid;
uint16_t pid;
} android_pmsg_log_header_t;
/* Header Structure to logd, and second header for pstore */
typedef struct __attribute__((__packed__)) {
uint8_t id;
uint16_t tid;
log_time realtime;
} android_log_header_t;
/* Event Header Structure to logd */
typedef struct __attribute__((__packed__)) {
int32_t tag; // Little Endian Order
} android_event_header_t;
// Event payload EVENT_TYPE_LIST
typedef struct __attribute__((__packed__)) {
int8_t type; // EVENT_TYPE_LIST
int8_t element_count;
} android_event_list_t;
// Event payload EVENT_TYPE_FLOAT
typedef struct __attribute__((__packed__)) {
int8_t type; // EVENT_TYPE_FLOAT
float data;
} android_event_float_t;
/* Event payload EVENT_TYPE_INT */
typedef struct __attribute__((__packed__)) {
int8_t type; // EVENT_TYPE_INT
int32_t data; // Little Endian Order
} android_event_int_t;
/* Event with single EVENT_TYPE_INT */
typedef struct __attribute__((__packed__)) {
android_event_header_t header;
android_event_int_t payload;
} android_log_event_int_t;
/* Event payload EVENT_TYPE_LONG */
typedef struct __attribute__((__packed__)) {
int8_t type; // EVENT_TYPE_LONG
int64_t data; // Little Endian Order
} android_event_long_t;
/* Event with single EVENT_TYPE_LONG */
typedef struct __attribute__((__packed__)) {
android_event_header_t header;
android_event_long_t payload;
} android_log_event_long_t;
/*
* Event payload EVENT_TYPE_STRING
*
* Danger: do not embed this structure into another structure.
* This structure uses a flexible array member, and when
* compiled using g++, __builtin_object_size(data, 1) returns
* a bad value. This is possibly a g++ bug, or a bug due to
* the fact that flexible array members are not supported
* in C++.
* http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
*/
typedef struct __attribute__((__packed__)) {
int8_t type; // EVENT_TYPE_STRING;
int32_t length; // Little Endian Order
char data[];
} android_event_string_t;
/* Event with single EVENT_TYPE_STRING */
typedef struct __attribute__((__packed__)) {
android_event_header_t header;
int8_t type; // EVENT_TYPE_STRING;
int32_t length; // Little Endian Order
char data[];
} android_log_event_string_t;
#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio,
const char* filename, const char* buf,
size_t len);
#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
typedef ssize_t (*__android_log_pmsg_file_read_fn)(log_id_t logId, char prio,
const char* filename,
const char* buf, size_t len,
void* arg);
ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio,
const char* prefix,
__android_log_pmsg_file_read_fn fn,
void* arg);
int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
int __android_log_security_bswrite(int32_t tag, const char* payload);
int __android_log_security(); /* Device Owner is present */
/* Retrieve the composed event buffer */
int android_log_write_list_buffer(android_log_context ctx, const char** msg);
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _INCLUDE_SYS_SYSTEM_PROPERTIES_H
#define _INCLUDE_SYS_SYSTEM_PROPERTIES_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct prop_info prop_info;
#define PROP_VALUE_MAX 255
/*
* Sets system property `name` to `value`, creating it if it doesn't exist.
*/
int __system_property_set(const char* __name,
const char* __value);
/*
* Returns a `prop_info` for system property `name`, or NULL if not found.
* Consider caching the result due to the expensive lookup.
*/
const prop_info* __system_property_find(const char* __name);
/*
* Calls `callback` with name, value, and serial number for property `pi`.
*/
void __system_property_read_callback(const prop_info* __pi,
void (*__callback)(void* __cookie, const char* __name, const char* __value, uint32_t __serial),
void* __cookie);
/*
* Iterates through all system properties and calls the provided callback for each.
* Primarily for debugging and inspection.
*/
int __system_property_foreach(void (*__callback)(const prop_info* __pi, void* __cookie), void* __cookie);
/*
* Waits for the system property `pi` to be updated past `old_serial`, with an optional timeout.
* If `pi` is NULL, waits for the global serial number.
*/
struct timespec;
bool __system_property_wait(const prop_info* __pi, uint32_t __old_serial, uint32_t* __new_serial_ptr, const struct timespec* __relative_timeout);
/* Deprecated: Property name length limit. */
#define PROP_NAME_MAX 127
/* Deprecated: Use __system_property_read_callback instead. */
int __system_property_read(const prop_info* __pi, char* __name, char* __value);
/* Deprecated: Use __system_property_read_callback instead. */
int __system_property_get(const char* __name, char* __value);
#if defined(__cplusplus)
}
#endif
#endif

283
kvdb/backend.c Normal file
View File

@ -0,0 +1,283 @@
/*
* Copyright (C) 2024 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <string.h>
#include <kvdb.h>
#include <sys/param.h>
#include <sys/stat.h>
#include "internal.h"
/****************************************************************************
* Private Functions
****************************************************************************/
static int kvdb_get_index(const char* key)
{
if (strncmp(key, PERSIST_LABEL, PERSIST_LABEL_LEN) == 0) {
return KVDB_PERSIST;
} else {
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
return KVDB_MEM;
#else
return -EINVAL;
#endif
}
}
static bool kvdb_kv_is_exist(struct kvdb* kvdb, const char* key,
size_t key_len, size_t val_len)
{
return kvdb_get(kvdb, key, key_len, NULL, val_len) >= 0;
}
static bool kvdb_is_readonly(const char* key)
{
return strncmp(key, "ro.", 3) == 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: kvdb_init
*
* Description:
* init resource of nvs .
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_init(struct kvdb** kvdb)
{
int ret = kvdb_persist_init(kvdb);
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
if (ret >= 0) {
ret = mkdir(CONFIG_KVDB_TEMPORARY_PATH, 0666);
if (ret < 0) {
ret = -errno;
/* Existing tmp dir is acceptable. */
if (ret == -EEXIST)
ret = 0;
}
}
#endif
return ret;
}
/****************************************************************************
* Name: kvdb_uninit
*
* Description:
* init resource of filekv .
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
void kvdb_uninit(struct kvdb* kvdb)
{
kvdb_persist_uninit(kvdb);
}
/****************************************************************************
* Name: kvdb_set
*
* Description:
* key-value set.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to set.
* key_len - the length of the key
* value - Pointer to data to be saved
* val_len - the length of the value
* force - unused parameter
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_set(struct kvdb* kvdb, const char* key, size_t key_len,
const void* value, size_t val_len, bool force)
{
int ret;
if (!force && kvdb_is_readonly(key) && kvdb_kv_is_exist(kvdb, key, key_len, val_len))
return -EPERM;
ret = kvdb_get_index(key);
switch (ret) {
case KVDB_PERSIST:
ret = kvdb_persist_set(kvdb, key, key_len, value, val_len, force);
break;
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
case KVDB_MEM:
ret = kvdb_file_set(CONFIG_KVDB_TEMPORARY_PATH, key, value, val_len);
break;
#endif
default:
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: kvdb_get
*
* Description:
* key-value get.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to get.
* key_len - the length of the key
* value - Pointer to data to be get
* val_len - the length of the value
*
* Returned Value:
* the length of value, > 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
ssize_t kvdb_get(struct kvdb* kvdb, const char* key, size_t key_len,
void* value, size_t val_len)
{
ssize_t ret = kvdb_get_index(key);
switch (ret) {
case KVDB_PERSIST:
ret = kvdb_persist_get(kvdb, key, key_len, value, val_len);
break;
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
case KVDB_MEM:
ret = kvdb_file_get(CONFIG_KVDB_TEMPORARY_PATH, key, value, val_len);
break;
#endif
default:
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: kvdb_delete
*
* Description:
* key-value delete.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to delete.
* key_len - the length of the key
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_delete(struct kvdb* kvdb, const char* key, size_t key_len)
{
int ret;
if (kvdb_is_readonly(key))
return -EPERM;
ret = kvdb_get_index(key);
switch (ret) {
case KVDB_PERSIST:
ret = kvdb_persist_delete(kvdb, key, key_len);
break;
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
case KVDB_MEM:
ret = kvdb_file_delete(CONFIG_KVDB_TEMPORARY_PATH, key);
break;
#endif
default:
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: kvdb_list
*
* key-value list.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* consume - callback when key-value fetch success.
* cookie - private data for consume callback.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
{
int ret = kvdb_persist_list(kvdb, consume, cookie);
if (ret < 0)
return ret;
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
ret = kvdb_file_list(CONFIG_KVDB_TEMPORARY_PATH, consume, cookie);
#endif
return ret;
}
/****************************************************************************
* Name: kvdb_commit
*
* key-value commit.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_commit(struct kvdb* kvdb)
{
/* Filekv over tmpfs always no need for commit */
return kvdb_persist_commit(kvdb);
}

864
kvdb/client.c Normal file
View File

@ -0,0 +1,864 @@
/*
* Copyright (C) 2023 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netpacket/rpmsg.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <kvdb.h>
#include "internal.h"
/****************************************************************************
* Private Functions
****************************************************************************/
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;
}
}
return -errno;
}
if (ret == 0)
return -ENODATA;
offset += ret;
}
return len;
}
/****************************************************************************
* Name: property_connect
*
* Description:
* Initialize client socket and connect to server
*
* Input Parameters:
* None
*
* Returned Value:
* On success return client socket fd.
* On error return error value (<0).
*
****************************************************************************/
static int property_connect(void)
{
#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,
};
#else
struct sockaddr_rpmsg addr = {
.rp_family = AF_RPMSG,
.rp_name = PROP_SERVER_PATH,
.rp_cpu = CONFIG_KVDB_SERVER_CPUNAME,
};
#endif
while (1) {
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);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: property_set_binary
*
* Description:
* Store Key-Values to database.
*
* Input Parameters:
* const char* key: entry key string
* const void* value: entry value string
* size_t val_len: the length of the value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
int property_set_binary(const char* key, const void* value, size_t val_len, bool oneway)
{
int fd;
if (!key)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
if (val_len == 0 || val_len >= PROP_VALUE_MAX)
return -E2BIG;
again:
fd = property_connect();
if (fd < 0) {
KVERR("connect failed, fd=%d\n", fd);
return fd;
}
/*-------------------------------------*
| 1 | 1 | 1 | key_len |val_len|
|-------------------------------------|
|'S'|key_len|val_len|[key'\0']|[value]|
*-------------------------------------*/
char cmd[3] = {
'S', key_len, val_len
};
struct iovec iov[3] = {
{ .iov_base = cmd, .iov_len = 3 },
{ .iov_base = (char*)key, .iov_len = key_len },
{ .iov_base = (char*)value, .iov_len = val_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 3;
int ret = sendmsg(fd, &msg, 0);
if (ret < 0) {
/* handle server refused by backlog limitation */
if (oneway && errno == ECONNRESET) {
close(fd);
goto again;
}
ret = -errno;
KVERR("sendmsg failed, ret=%d\n", ret);
goto out;
}
if (!oneway) {
/*-----*
| 4 |
|-----|
|error|
*-----*/
int32_t err;
ret = recv(fd, &err, 4, 0);
if (ret < 4) {
KVERR("recv failed, ret=%d\n", ret);
ret = ret < 0 ? -errno : -EINVAL;
goto out;
}
ret = err;
}
out:
close(fd);
return ret;
}
/****************************************************************************
* Name: property_get_binary
*
* Description:
* Retrieve Key-Values from database.
*
* Input Parameters:
* const char* key: entry key string
* void* value: not NULL : pointer to string buffer
* NULL : check whether this [key, value] exists
* size_t val_len: the length of the value
*
* Returned Value:
* On success returns the length of the value which will never be greater
* than PROP_NAME_MAX.
*
****************************************************************************/
ssize_t property_get_binary(const char* key, void* value, size_t val_len)
{
if (!key)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -EINVAL;
int fd = property_connect();
if (fd < 0) {
KVERR("connect failed, fd=%d\n", fd);
return fd;
}
/*-----------------------------*
| 1 | 1 | key_len |val_len|
| --------------------|-------|
|'G'|key_len|[key'\0']|[value]|
*-----------------------------*/
char cmd[3] = {
'G', key_len, val_len
};
struct iovec iov[2] = {
{ .iov_base = cmd, .iov_len = 3 },
{ .iov_base = (char*)key, .iov_len = key_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 2;
ssize_t len = -1;
int ret = sendmsg(fd, &msg, 0);
if (ret < 0) {
KVERR("sendmsg failed, errno=%d\n", errno);
goto out;
}
/*-------*
|val_len|
|-------|
|[value]|
*-------*/
if (value) {
/* value is not NULL, receive all the value */
len = recv(fd, value, val_len, 0);
if (len <= 0) {
if (len != 0) {
KVERR("recv failed, len=%d\n", len);
}
goto out;
}
} else {
/* value is NULL, receive two chars to check whether this
* [key, value] exists
*/
char tmpvalue[1];
len = recv(fd, tmpvalue, 1, 0);
if (len <= 0) {
if (len != 0) {
KVERR("recv failed, len=%d\n", len);
}
}
}
out:
close(fd);
return len < 0 ? -errno : len;
}
/****************************************************************************
* Name: property_delete
*
* Description:
* Delete a KV pair by key
*
* Input Parameters:
* const char* key: entry key string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
int property_delete(const char* key)
{
if (!key)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
/* in environment variable? */
if (getenv(key)) {
int ret = unsetenv(key);
if (ret < 0)
ret = -errno;
return ret;
}
int fd = property_connect();
if (fd < 0) {
KVERR("connect failed, fd=%d\n", fd);
return fd;
}
/*---------------------*
| 1 | 1 | key_len |
| --------------------|
|'D'|key_len|[key'\0']|
*---------------------*/
char cmd[2] = {
'D', key_len
};
struct iovec iov[2] = {
{ .iov_base = cmd, .iov_len = 2 },
{ .iov_base = (char*)key, .iov_len = key_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 2;
int ret = sendmsg(fd, &msg, 0);
if (ret < 0) {
ret = -errno;
KVERR("sendmsg failed, ret=%d\n", ret);
goto out;
}
/*-----*
| 4 |
|-----|
|error|
*-----*/
int32_t err;
ret = recv(fd, &err, 4, 0);
if (ret < 4) {
KVERR("recv failed, ret=%d\n", ret);
ret = ret < 0 ? -errno : -EINVAL;
goto out;
}
ret = err;
out:
close(fd);
return ret;
}
/****************************************************************************
* Name: property_list_binary
*
* Description:
* List all KVs in every database and calls callback function.
*
* Input Parameters:
* property_callback propfn: callback function
* void* cookie: cookie data to pass to callback function
*
* Returned Value:
* 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)
{
char* msg = NULL;
int fd = property_connect();
if (fd < 0) {
KVERR("connect failed, fd=%d\n", fd);
return fd;
}
/*---*
| 1 |
| --|
|'L'|
*---*/
int ret = send(fd, "L", 1, 0);
if (ret < 0) {
ret = -errno;
KVERR("send failed, ret=%d\n", ret);
goto out;
}
msg = malloc(PROP_MSG_MAX);
if (msg == NULL) {
KVERR("malloc failed\n");
ret = -ENOMEM;
goto out;
}
while (1) {
/*---------------------------------*
| 1 | 1 | key_len |val_len|
|---------------------------------|
|key_len|val_len|[key'\0']|[value]|
*---------------------------------*/
ret = recv_safe(fd, msg, 0, 2);
if (ret < 0) {
ret = -errno;
KVERR("recv_safe failed, ret=%d\n", ret);
goto out;
}
if (msg[0] == 0 && msg[1] == 0) {
/* end of list */
ret = 0;
break;
}
size_t key_len = (unsigned char)msg[0];
if (key_len > PROP_NAME_MAX)
continue;
size_t val_len = (unsigned char)msg[1];
if (val_len >= PROP_VALUE_MAX)
continue;
size_t total = key_len + val_len + 2;
ret = recv_safe(fd, msg, 2, total);
if (ret < 0) {
KVERR("recv_safe failed, ret=%d\n", ret);
break;
}
const char* key = msg + 2;
void* value = msg + 2 + key_len;
if (key[key_len - 1])
continue;
propfn(key, value, val_len, cookie);
}
out:
free(msg);
close(fd);
return ret;
}
/****************************************************************************
* Name: property_wait
*
* Description:
* Wait the monitored key until its value updated or key deleted.
*
* Input Parameters:
* const char* key : the monitored key string, support fnmatch pattern
* char* newkey : pointer to a string buffer to receive the key of
* the updated/deleted value
* void* newvalue: pointer to a string buffer to receive the updated
* value or deleted value
* size_t val_len : the length of the newvalue
* int timeout : the wait timeout time (in milliseconds)
*
* Returned Value:
* On success returns the length of the value.
*
****************************************************************************/
ssize_t property_wait(const char* key, char* newkey, void* newvalue, size_t val_len, int timeout)
{
if (key == NULL)
return -EINVAL;
int fd = property_monitor_open(key);
if (fd < 0)
return fd;
struct pollfd fds = {
.fd = fd,
.events = POLLIN
};
int ret = poll(&fds, 1, timeout);
if (ret < 0) {
ret = -errno;
KVERR("poll failed, ret=%d\n", ret);
goto out;
} else if (ret == 0 || (fds.revents & POLLIN) == 0) {
ret = -ETIMEDOUT;
goto out;
}
ret = property_monitor_read(fd, newkey, newvalue, val_len);
out:
property_monitor_close(fd);
return ret;
}
/****************************************************************************
* Name: property_monitor_open
*
* Description:
* Open a key monitor channel
*
* Input Parameters:
* const char* key : the monitored key string, support fnmatch pattern
*
* Returned Value:
* On success returns a file descriptor, -errno otherwise.
*
****************************************************************************/
int property_monitor_open(const char* key)
{
if (key == NULL)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
int fd = property_connect();
if (fd < 0) {
KVERR("connect failed, fd=%d\n", fd);
return fd;
}
/*------------------------*
| 1 | 1 | key_len |
|-------|-----------------|
| 'M' |key_len|[key'\0']|
*-------------------------*/
char cmd[2] = { 'M', key_len };
struct iovec iov[2] = {
{ .iov_base = cmd, .iov_len = 2 },
{ .iov_base = (char*)key, .iov_len = key_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 2;
int ret = sendmsg(fd, &msg, 0);
if (ret < 0) {
KVERR("sendmsg failed, ret=%d\n", ret);
ret = -errno;
goto out;
}
/*-----*
| 4 |
|-----|
|error|
*-----*/
int32_t err;
ret = recv(fd, &err, 4, 0);
if (ret < 4) {
KVERR("recv failed, ret=%d\n", ret);
ret = ret < 0 ? -errno : -EINVAL;
goto out;
}
if (err < 0) {
ret = err;
goto out;
}
return fd;
out:
close(fd);
return ret;
}
/****************************************************************************
* Name: property_monitor_read
*
* Description:
* Wait the monitored key until its value updated or key deleted.
*
* Input Parameters:
* int fd : file descriptor returned by property_monitor_open()
* char* newkey : pointer to a strint buffer to receive the key of the
* updated/deleted value
* void* newvalue: pointer to a string buffer to receive the updated
* value or deleted value
* size_t val_len: newvalue length
*
* Returned Value:
* On success returns the length of the value.
*
****************************************************************************/
ssize_t property_monitor_read(int fd, char* newkey, void* newvalue, size_t val_len)
{
char* msg = malloc(PROP_MSG_MAX);
if (msg == NULL) {
KVERR("malloc failed\n");
return -ENOMEM;
}
ssize_t ret = recv(fd, msg, 2, 0);
if (ret < 2) {
KVERR("recv failed, ret=%d, errno=%d\n", ret, errno);
free(msg);
return ret < 0 ? -errno : -ENODATA;
}
size_t key_len = (unsigned char)msg[0];
if (key_len > PROP_NAME_MAX) {
free(msg);
return -E2BIG;
}
size_t len = (unsigned char)msg[1];
if (len > PROP_VALUE_MAX) {
free(msg);
return -E2BIG;
}
size_t total = key_len + len + 2;
ret = recv_safe(fd, msg, ret, total);
if (ret < 0) {
KVERR("recv_safe failed, ret=%d\n", ret);
free(msg);
return ret;
}
const char* key = &msg[2];
if (newkey != NULL)
strlcpy(newkey, key, PROP_NAME_MAX);
if (newvalue != NULL) {
/*--------------------------------*
| 1 | 1 | key_len |val_len|
|---------------------------------|
|key_len|val_len|[key'\0']|[value]|
*---------------------------------*/
const void* value = &msg[2 + key_len];
len = val_len > len ? len : val_len;
memcpy(newvalue, value, len);
}
free(msg);
return len;
}
/****************************************************************************
* Name: property_monitor_close
*
* Description:
* Close a key monitor channel
*
* Input Parameters:
* int fd : file descriptor returned by property_monitor_open()
*
* Returned Value:
* On success returns 0, -errno otherwise.
*
****************************************************************************/
int property_monitor_close(int fd)
{
int ret = close(fd);
if (ret < 0)
ret = -errno;
return ret;
}
/****************************************************************************
* Name: property_commit
*
* Description:
* Actively commit all property changes
*
* Input Parameters:
* None
*
* Returned Value:
* On success returns 0.
* On failure returns -errno.
*
****************************************************************************/
int property_commit(void)
{
int fd = property_connect();
int ret;
int value;
if (fd < 0)
return fd;
ret = send(fd, "C", 1, 0);
if (ret < 0) {
KVERR("send error %d\n", errno);
ret = -errno;
goto out;
}
ret = recv(fd, &value, sizeof(value), 0);
if (ret < sizeof(value)) {
KVERR("recv error %d, ret %d\n", errno, ret);
ret = -errno;
goto out;
}
ret = value;
if (ret < 0) {
KVERR("commit error %d\n", ret);
}
out:
close(fd);
return ret;
}
/****************************************************************************
* Name: property_load
*
* Description:
* load default property value
*
* Input Parameters:
* const char* path: file path
*
* Returned Value:
* On success returns 0.
* On failure returns -errno.
*
****************************************************************************/
int property_load(const char* path)
{
size_t file_len;
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;
close(fd);
return ret;
}
/****************************************************************************
* Name: property_exit
*
* Description:
* Exit Kvdb Server
*
* Input Parameters:
* None
*
* Returned Value:
* On success returns 0.
* On failure returns -errno.
*
****************************************************************************/
int property_exit(void)
{
int fd = property_connect();
int ret;
int value;
if (fd < 0)
return fd;
ret = send(fd, "E", 1, 0);
if (ret < 0) {
KVERR("send error %d\n", errno);
ret = -errno;
goto out;
}
ret = recv(fd, &value, sizeof(value), 0);
if (ret < sizeof(value)) {
KVERR("recv error %d, ret %d\n", errno, ret);
ret = -errno;
}
out:
close(fd);
return ret;
}

639
kvdb/common.c Normal file
View File

@ -0,0 +1,639 @@
/*
* Copyright (C) 2023 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <kvdb.h>
#include "internal.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct property_list_arg {
void* cookie;
void (*propfn)(const char* key, const char* value, void* cookie);
};
/****************************************************************************
* Private Functions
****************************************************************************/
static void property_list_fn(const char* key, const void* value, size_t val_len, void* cookie)
{
struct property_list_arg* list = (struct property_list_arg*)cookie;
*((char*)value + val_len) = '\0';
list->propfn(key, value, list->cookie);
}
static inline char nibble2ascii(unsigned char nibble)
{
if (nibble < 10)
return '0' + nibble;
else
return 'a' + nibble - 10;
}
static inline int ascii2nibble(char ascii)
{
if (isdigit(ascii))
return ascii - '0';
else if (isxdigit(ascii))
return tolower(ascii) - 'a' + 10;
else
return -ERANGE;
}
/****************************************************************************
* Name: property_set_
*
* Description:
* Store Key-Values to database.
*
* Input Parameters:
* const char* key: entry key string
* const char* value: entry value string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_(const char* key, const char* value, bool oneway)
{
if (!value)
value = "";
/* in environment variable? */
if (getenv(key)) {
int ret = setenv(key, value, 1);
if (ret < 0)
ret = -errno;
return ret;
}
return property_set_binary(key, value, strlen(value) + 1, oneway);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: property_set
*
* Description:
* Store Key-Values to database.
*
* Input Parameters:
* const char* key: entry key string
* const char* value: entry value string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
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
*
* 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
* const char* default_value: the value to return on failure
*
* 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 length of default_value.
*
****************************************************************************/
int property_get(const char* key, char* value, const char* default_value)
{
int ret = property_get_with_err(key, value);
if (ret <= 0) {
if (!default_value)
return -EINVAL;
size_t len = strlen(default_value);
if (value)
memcpy(value, default_value, len + 1);
return len;
}
return ret;
}
/****************************************************************************
* Name: property_list
*
* Description:
* List all KVs in every database and calls callback function.
*
* Input Parameters:
* property_callback propfn: callback function
* void* cookie: cookie data to pass to callback function
*
* Returned Value:
* Returns 0 on success, <0 if all databases failed to open.
*
****************************************************************************/
int property_list(void (*propfn)(const char* key, const char* value, void* cookie), void* cookie)
{
struct property_list_arg list;
list.cookie = cookie;
list.propfn = propfn;
return property_list_binary(property_list_fn, &list);
}
int property_set_oneway(const char* key, const char* value)
{
return property_set_(key, value, true);
}
/****************************************************************************
* Name: property_set_bool
*
* Description:
* Saves a boolean to database.
*
* Input Parameters:
* const char* key: entry key string
* int8_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_bool_(const char* key, int8_t value, bool oneway)
{
return property_set_(key, value ? "true" : "false", oneway);
}
int property_set_bool(const char* key, int8_t value)
{
return property_set_bool_(key, value, false);
}
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
*
* Description:
* Retrieve a Key-Value from backend and interpret the value as boolean.
* This is taken from Android libcutils:
* https://android.googlesource.com/platform/system/core/+/master/libcutils/
* properties.cpp
*
* Input Parameters:
* const char* key: entry key string
* int8_t default_value: the value to return on failure
*
* Returned Value:
* On success returns a boolean.
* On failure returns default_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);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_int32
*
* Description:
* Saves an 32-bit integer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* int32_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_int32_(const char* key, int32_t value, bool oneway)
{
char buf[32];
snprintf(buf, 32, "%" PRId32, value);
return property_set_(key, buf, oneway);
}
int property_set_int32(const char* key, int32_t value)
{
return property_set_int32_(key, value, false);
}
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
*
* 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 default_value: the value to return on failure
*
* Returned Value:
* On success returns a int32_t.
* On failure returns default_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);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_int64
*
* Description:
* Saves an 64-bit integer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* int64_t value: entry value
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_int64_(const char* key, int64_t value, bool oneway)
{
char buf[32];
snprintf(buf, 32, "%" PRId64, value);
return property_set_(key, buf, oneway);
}
int property_set_int64(const char* key, int64_t value)
{
return property_set_int64_(key, value, false);
}
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
*
* 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 default_value: the value to return on failure
*
* Returned Value:
* On success returns a int64_t.
* On failure returns default_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);
return ret ? default_value : value;
}
/****************************************************************************
* Name: property_set_buffer
*
* Description:
* Saves a binary buffer to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* const void* value: buffer value
* size_t size: buffer size
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
static int property_set_buffer_(const char* key, const void* value,
size_t size, bool oneway)
{
size_t buf_size = 2 * size;
if (buf_size >= PROP_VALUE_MAX)
return -E2BIG;
const unsigned char* tmp = value;
char buf[PROP_VALUE_MAX];
size_t i = 0;
while (i < buf_size) {
buf[i++] = nibble2ascii(*tmp >> 4);
buf[i++] = nibble2ascii(*tmp++ & 0x0f);
}
buf[i] = '\0';
return property_set_(key, buf, oneway);
}
int property_set_buffer(const char* key, const void* value, size_t size)
{
return property_set_buffer_(key, value, size, false);
}
int property_set_buffer_oneway(const char* key, const void* value, size_t size)
{
return property_set_buffer_(key, value, size, false);
}
/****************************************************************************
* Name: property_get_buffer
*
* Description:
* Retrieve a Key-Value from backend and interpret as binary buffer.
*
* Input Parameters:
* const char* key: entry key string
* void* value: buffer value
* size_t size: buffer size
*
* Returned Value:
* On success returns buffer length.
* On failure returns -errno.
*
****************************************************************************/
ssize_t property_get_buffer(const char* key, void* value, size_t size)
{
char buf[PROP_VALUE_MAX];
size_t buf_size = 2 * size;
int ret = property_get(key, buf, NULL);
if (ret < 0)
return ret;
char* tmp = value;
size_t i = 0;
while (buf[i]) {
if (i >= buf_size)
return -E2BIG;
ret = ascii2nibble(buf[i++]);
if (ret < 0)
return ret;
*tmp = ret << 4;
ret = ascii2nibble(buf[i++]);
if (ret < 0)
return ret;
*tmp++ |= ret;
}
return i / 2;
}

224
kvdb/direct.c Normal file
View File

@ -0,0 +1,224 @@
/*
* Copyright (C) 2023 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kvdb.h>
#include "internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: property_set_binary
*
* Description:
* Store Key-Values to unqlite backend or nvs backend.
*
* Input Parameters:
* const char* key: entry key string
* const void* value: entry value string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
int property_set_binary(const char* key, const void* value, size_t val_len, bool oneway)
{
if (!key)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
if (val_len == 0 || val_len >= PROP_VALUE_MAX)
return -E2BIG;
struct kvdb* client;
int ret = kvdb_init(&client);
if (ret < 0)
return ret;
ret = kvdb_set(client, key, key_len, value, val_len, false);
kvdb_uninit(client);
return ret;
}
/****************************************************************************
* Name: property_get_binary
*
* Description:
* Retrieve Key-Values from database.
*
* Input Parameters:
* const char* key: entry key string
* void* 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.
*
****************************************************************************/
ssize_t property_get_binary(const char* key, void* value, size_t val_len)
{
if (!key)
return -E2BIG;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
struct kvdb* client;
int ret = kvdb_init(&client);
if (ret < 0)
return ret;
ssize_t len = kvdb_get(client, key, key_len, value, val_len);
kvdb_uninit(client);
return len;
}
/****************************************************************************
* Name: property_delete
*
* Description:
* Delete a KV pair by key
*
* Input Parameters:
* const char* key: entry key string
*
* Returned Value:
* 0: success
* <0: failure during execution
*
****************************************************************************/
int property_delete(const char* key)
{
if (!key)
return -EINVAL;
size_t key_len = strlen(key) + 1;
if (key_len > PROP_NAME_MAX)
return -E2BIG;
/* in environment variable? */
if (getenv(key)) {
int ret = unsetenv(key);
if (ret < 0)
ret = -errno;
return ret;
}
struct kvdb* client;
int ret = kvdb_init(&client);
if (ret < 0)
return ret;
ret = kvdb_delete(client, key, key_len);
kvdb_uninit(client);
return ret;
}
/****************************************************************************
* Name: property_list
*
* Description:
* List all KVs.
*
* Input Parameters:
* property_callback propfn: callback function
* void* cookie: cookie data to pass to callback function
*
* Returned Value:
* Returns 0 on success, <0 if all backend failed to open.
*
****************************************************************************/
int property_list_binary(void (*propfn)(const char* key, const void* value, size_t val_len, void* cookie), void* cookie)
{
struct kvdb* client;
int ret = kvdb_init(&client);
if (ret < 0)
return ret;
ret = kvdb_list(client, propfn, cookie);
kvdb_uninit(client);
return ret;
}
/****************************************************************************
* Name: property_commit
*
* Description:
* Actively commit all property changes
*
* Input Parameters:
* None
*
****************************************************************************/
int property_commit(void)
{
return 0;
}
/****************************************************************************
* Name: property_load
*
* Description:
* load default property value
*
* Input Parameters:
* const char* path: file path
*
****************************************************************************/
int property_load(const char* path)
{
return 0;
}
/****************************************************************************
* Name: property_exit
*
* Description:
* Exit Kvdb Server (Dummy Function)
*
* Input Parameters:
* None
*
****************************************************************************/
int property_exit(void)
{
return 0;
}

22
kvdb/exitprop.c Normal file
View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 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 <kvdb.h>
int main(int argc, char* argv[])
{
return property_exit();
}

330
kvdb/file.c Normal file
View File

@ -0,0 +1,330 @@
/*
* Copyright (C) 2020 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "internal.h"
#include "kvdb.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* kvdb_file_genpath
****************************************************************************/
static void kvdb_file_genpath(const char* path, const char* key, char* filepath)
{
snprintf(filepath, PATH_MAX, "%s/%s", path, key);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* kvdb_file_set
****************************************************************************/
int kvdb_file_set(const char* path, const char* key,
const void* value, size_t val_len)
{
char filepath[PATH_MAX];
size_t nbyteswrite = 0;
ssize_t result;
int fd;
kvdb_file_genpath(path, key, filepath);
fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666);
if (fd < 0) {
KVERR("open %s error with %d", filepath, errno);
return -errno;
}
while (nbyteswrite < val_len) {
result = write(fd, value, val_len);
if (result < 0) {
if (result == -EINTR) {
continue;
}
KVERR("write %s error with %d", filepath, errno);
close(fd);
return -errno;
}
nbyteswrite += result;
}
close(fd);
return 0;
}
/****************************************************************************
* kvdb_file_get
****************************************************************************/
ssize_t kvdb_file_get(const char* path, const char* key,
void* value, size_t val_len)
{
char filepath[PATH_MAX];
size_t nbytesread = 0;
ssize_t result;
ssize_t ret;
int fd;
kvdb_file_genpath(path, key, filepath);
if (value == NULL) {
/* Readonly property only check if exist, no read required. */
if (access(filepath, O_RDONLY) == 0)
return val_len;
else
return -ENOENT;
}
fd = open(filepath, O_RDONLY | O_CLOEXEC, 0666);
if (fd < 0) {
KVERR("open %s error with %d", filepath, errno);
return -errno;
}
do {
result = read(fd, value + nbytesread, val_len - nbytesread);
if (result < 0) {
result = -errno;
if (result == -EINTR) {
continue;
}
KVERR("read %s error with %d", filepath, errno);
ret = -errno;
close(fd);
return ret;
}
nbytesread += result;
} while (result > 0 && nbytesread < val_len);
ret = nbytesread;
close(fd);
return ret;
}
/****************************************************************************
* kvdb_file_list
****************************************************************************/
int kvdb_file_list(const char* path, kvdb_consume consume, void* cookie)
{
char value[PROP_VALUE_MAX];
struct dirent* entry;
int ret = 0;
DIR* dir;
dir = opendir(path);
if (!dir) {
KVERR("opendir %s error with %d", path, errno);
return -errno;
}
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type != DT_REG) {
continue;
}
ret = kvdb_file_get(path, entry->d_name, value, PROP_VALUE_MAX);
if (ret < 0) {
ret = -errno;
break;
}
consume(entry->d_name, value, ret, cookie);
ret = 0;
}
closedir(dir);
return ret;
}
/****************************************************************************
* kvdb_file_delete
****************************************************************************/
int kvdb_file_delete(const char* path, const char* key)
{
char filepath[PATH_MAX];
kvdb_file_genpath(path, key, filepath);
return unlink(filepath);
}
#ifdef CONFIG_KVDB_FILE
/****************************************************************************
* Name: kvdb_persist_init
*
* Description:
* init resource of nvs .
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_init(struct kvdb** kvdb)
{
return 0;
}
/****************************************************************************
* Name: kvdb_persist_uninit
*
* Description:
* init resource of filekv .
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
void kvdb_persist_uninit(struct kvdb* kvdb)
{
}
/****************************************************************************
* Name: kvdb_persist_set
*
* Description:
* key-value set.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to set.
* key_len - the length of the key
* value - Pointer to data to be saved
* val_len - the length of the value
* force - unused parameter
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_set(struct kvdb* kvdb, const char* key, size_t key_len,
const void* value, size_t val_len, bool force)
{
return kvdb_file_set(CONFIG_KVDB_PERSIST_PATH, key, value, val_len);
}
/****************************************************************************
* Name: kvdb_persist_get
*
* Description:
* key-value get.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to get.
* key_len - the length of the key
* value - Pointer to data to be get
* val_len - the length of the value
*
* Returned Value:
* the length of value, > 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len,
void* value, size_t val_len)
{
return kvdb_file_get(CONFIG_KVDB_PERSIST_PATH, key, value, val_len);
}
/****************************************************************************
* Name: kvdb_persist_delete
*
* Description:
* key-value delete.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* key - Pointer to key to delete.
* key_len - the length of the key
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_delete(struct kvdb* kvdb, const char* key, size_t key_len)
{
return kvdb_file_delete(CONFIG_KVDB_PERSIST_PATH, key);
}
/****************************************************************************
* Name: kvdb_persist_list
*
* key-value list.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
* consume - callback when key-value fetch success.
* cookie - private data for consume callback.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
{
return kvdb_file_list(CONFIG_KVDB_PERSIST_PATH, consume, cookie);
}
/****************************************************************************
* Name: kvdb_persist_commit
*
* key-value commit.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_commit(struct kvdb* kvdb)
{
return 0;
}
#endif

68
kvdb/getprop.c Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2020 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 <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <kvdb.h>
static void callback(const char* name, const void* value, size_t val_len, void* cookie)
{
const char* temp = value;
ssize_t i;
for (i = 0; i < val_len; i++) {
if (!isprint(temp[i]))
break;
}
if (name != NULL)
printf("%s: ", name);
/* All previous characters can be printed and ending '\0' */
if (i == val_len - 1 && temp[i] == '\0') {
printf("%s\n", temp);
} else {
for (i = 0; i < val_len; i++)
printf("%02x", temp[i]);
printf("\n");
}
}
int main(int argc, char* argv[])
{
int ret = 0;
if (argc == 2 && strncmp(argv[1], "-h", 3)) {
char buf[PROP_VALUE_MAX];
ssize_t len = property_get_binary(argv[1], buf, sizeof(buf));
if (len < 0)
return len;
callback(NULL, buf, len, NULL);
}
#ifdef CONFIG_KVDB_DUMPLIST
else if (argc == 1)
ret = -property_list_binary(callback, NULL);
#endif
else
printf("Usage: %s [key]\n", argv[0]);
return ret;
}

95
kvdb/internal.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2023 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.
*/
#ifndef __INTERNAL_H
#define __INTERNAL_H
#include <stddef.h>
#include <syslog.h>
#define KVLOG(level, fmt, ...) \
syslog(level, "[kvdb] [%s:%d] " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#if defined(CONFIG_KVDB_LOG_INFO)
#define KVINFO(fmt, ...) KVLOG(LOG_INFO, fmt, ##__VA_ARGS__)
#define KVWARN(fmt, ...) KVLOG(LOG_WARNING, fmt, ##__VA_ARGS__)
#define KVERR(fmt, ...) KVLOG(LOG_ERR, fmt, ##__VA_ARGS__)
#elif defined(CONFIG_KVDB_LOG_WARN)
#define KVINFO(fmt, ...)
#define KVWARN(fmt, ...) KVLOG(LOG_WARNING, fmt, ##__VA_ARGS__)
#define KVERR(fmt, ...) KVLOG(LOG_ERR, fmt, ##__VA_ARGS__)
#elif defined(CONFIG_KVDB_LOG_ERR)
#define KVINFO(fmt, ...)
#define KVWARN(fmt, ...)
#define KVERR(fmt, ...) KVLOG(LOG_ERR, fmt, ##__VA_ARGS__)
#else
#define KVINFO(fmt, ...)
#define KVWARN(fmt, ...)
#define KVERR(fmt, ...)
#endif
#define PROP_SERVER_PATH "kvdbd"
#if defined(__cplusplus)
extern "C" {
#endif
#define PERSIST_LABEL "persist."
#define PERSIST_LABEL_LEN 8
/****************************************************************************
* Public Type Definitions
****************************************************************************/
enum {
KVDB_PERSIST, /* save key-value pairs in flash */
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
KVDB_MEM, /* save key-value pairs in memory */
#endif
};
struct kvdb;
typedef void (*kvdb_consume)(const char* key, const void* value, size_t val_len, void* cookie);
int kvdb_set(struct kvdb* kvdb, const char* key, size_t key_len, const void* value, size_t val_len, bool force);
ssize_t kvdb_get(struct kvdb* kvdb, const char* key, size_t key_len, void* value, size_t val_len);
int kvdb_delete(struct kvdb* kvdb, const char* key, size_t key_len);
int kvdb_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie);
int kvdb_commit(struct kvdb* kvdb);
int kvdb_init(struct kvdb** kvdb);
void kvdb_uninit(struct kvdb* kvdb);
int kvdb_persist_init(struct kvdb** kvdb);
void kvdb_persist_uninit(struct kvdb* kvdb);
int kvdb_persist_commit(struct kvdb* kvdb);
int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie);
ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len, void* value, size_t val_len);
int kvdb_persist_set(struct kvdb* kvdb, const char* key, size_t key_len, const void* value, size_t val_len, bool force);
int kvdb_persist_delete(struct kvdb* kvdb, const char* key, size_t key_len);
#ifdef CONFIG_KVDB_TEMPORARY_STORAGE
int kvdb_file_set(const char* path, const char* key, const void* value, size_t val_len);
ssize_t kvdb_file_get(const char* path, const char* key, void* value, size_t val_len);
int kvdb_file_list(const char* path, kvdb_consume consume, void* cookie);
int kvdb_file_delete(const char* path, const char* key);
#endif
#if defined(__cplusplus)
}
#endif
#endif /* __INTERNAL_H */

322
kvdb/nvs.c Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (C) 2020 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <nuttx/mtd/configdata.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "internal.h"
#include "kvdb.h"
/****************************************************************************
* Private Type Definitions
****************************************************************************/
struct kvdb {
int fd;
};
/****************************************************************************
* Private Functions
****************************************************************************/
static inline const char* kvdb_skip_prefix(const char* key)
{
return key + PERSIST_LABEL_LEN;
}
static void kvdb_add_prefix(char* out, size_t outlen, const char* in)
{
strlcpy(out, PERSIST_LABEL, outlen);
strlcat(out, in, outlen);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: kvdb_persist_init
*
* Description:
* init resource of nvs .
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_init(struct kvdb** kvdb)
{
struct kvdb* handle;
int ret;
handle = (struct kvdb*)zalloc(sizeof(struct kvdb));
if (handle == NULL) {
KVERR("kvdb init error !\n");
return -ENOMEM;
}
ret = open(CONFIG_KVDB_PERSIST_PATH, O_RDWR | O_CLOEXEC);
if (ret < 0) {
ret = -errno;
KVERR("open %s error with %d", CONFIG_KVDB_PERSIST_PATH, ret);
goto err;
}
handle->fd = ret;
*kvdb = handle;
return 0;
err:
free(handle);
return ret;
}
/****************************************************************************
* Name: kvdb_persist_uninit
*
* Description:
* init resource of nvs .
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
void kvdb_persist_uninit(struct kvdb* kvdb)
{
close(kvdb->fd);
free(kvdb);
}
/****************************************************************************
* Name: kvdb_persist_set
*
* Description:
* key-value set.
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
* key - Pointer to key to set.
* key_len - the length of the key
* value - Pointer to data to be saved
* val_len - the length of the value
* force - unused parameter
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_set(struct kvdb* kvdb, const char* key, size_t key_len,
const void* value, size_t val_len, bool force)
{
struct config_data_s data;
int ret;
key = kvdb_skip_prefix(key);
if (strlen(key) >= sizeof(data.name))
return -EINVAL;
strlcpy(data.name, key, sizeof(data.name));
data.len = val_len;
data.configdata = (uint8_t*)value;
ret = ioctl(kvdb->fd, CFGDIOC_SETCONFIG, &data);
if (ret < 0) {
ret = -errno;
KVERR("IOCTL_SETCONFIG ERROR %d", ret);
}
return ret;
}
/****************************************************************************
* Name: kvdb_persist_get
*
* Description:
* key-value get.
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
* key - Pointer to key to get.
* key_len - the length of the key
* value - Pointer to data to be get
* val_len - the length of the value
*
* Returned Value:
* the length of value, > 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len, void* value, size_t val_len)
{
struct config_data_s data;
int ret;
if (key == NULL || key_len == 0)
return -EINVAL;
key = kvdb_skip_prefix(key);
if (strlen(key) >= sizeof(data.name))
return -EINVAL;
strlcpy(data.name, key, sizeof(data.name));
data.configdata = (uint8_t*)value;
data.len = val_len;
ret = ioctl(kvdb->fd, CFGDIOC_GETCONFIG, &data);
if (ret < 0) {
ret = -errno;
KVERR("CFGDIOC_GETCONFIG ERROR: %d", ret);
return ret;
}
return data.len;
}
/****************************************************************************
* Name: kvdb_persist_delete
*
* Description:
* key-value delete.
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
* key - Pointer to key to delete.
* key_len - the length of the key
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_delete(struct kvdb* kvdb, const char* key, size_t key_len)
{
struct config_data_s data;
int ret;
key = kvdb_skip_prefix(key);
if (strlen(key) >= sizeof(data.name))
return -EINVAL;
strlcpy(data.name, key, sizeof(data.name));
ret = ioctl(kvdb->fd, CFGDIOC_DELCONFIG, &data);
if (ret < 0) {
ret = -errno;
KVERR("CFGDIOC_DELCONFIG ERROR: %d", ret);
}
return ret;
}
/****************************************************************************
* Name: kvdb_persist_list
*
* Description:
* key-value list.
*
* Input Parameters:
* kvdb - Pointer to save nvs kvdb instance.
* consume - callback when key-value fetch success.
* cookie - private data for consume callback.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
{
char key[CONFIG_NAME_MAX + PERSIST_LABEL_LEN];
uint8_t buf[PROP_VALUE_MAX];
struct config_data_s data;
int ret;
if (!consume)
return 0;
data.configdata = buf;
data.len = PROP_VALUE_MAX;
ret = ioctl(kvdb->fd, CFGDIOC_FIRSTCONFIG, &data);
if (ret < 0)
return ret;
kvdb_add_prefix(key, sizeof(key), data.name);
consume(key, data.configdata, data.len, cookie);
while (1) {
data.configdata = buf;
data.len = PROP_VALUE_MAX;
ret = ioctl(kvdb->fd, CFGDIOC_NEXTCONFIG, &data);
if (ret < 0) {
ret = -errno;
/* ENOENT is expected when there are no more entries */
if (ret == -ENOENT)
ret = 0;
break;
}
kvdb_add_prefix(key, sizeof(key), data.name);
consume(key, data.configdata, data.len, cookie);
}
return ret;
}
/****************************************************************************
* Name: kvdb_persist_commit
*
* key-value commit.
*
* Input Parameters:
* kvdb - Pointer to save filekv instance.
*
* Returned Value:
* 0 on success, -ERRNO errno code if error.
*
****************************************************************************/
int kvdb_persist_commit(struct kvdb* kvdb)
{
return 0;
}

264
kvdb/qemu_properties.c Normal file
View File

@ -0,0 +1,264 @@
/****************************************************************************
* frameworks/utils/kvdb/qemu_properties.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <kvdb.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MAX_TRIES 5
#define BUFF_SIZE (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
/****************************************************************************
* Private Functions
****************************************************************************/
static int
qemu_pipe_open_ns(const char* ns, const char* pipe_name, int flags)
{
char buf[PATH_MAX];
int buf_len;
int fd = open("/dev/goldfish_pipe", flags);
if (fd < 0) {
return -errno;
}
if (ns) {
buf_len = snprintf(buf, sizeof(buf), "pipe:%s:%s", ns, pipe_name);
} else {
buf_len = snprintf(buf, sizeof(buf), "pipe:%s", pipe_name);
}
if (write(fd, buf, buf_len + 1) < 0) {
fprintf(stderr, "%s:%d: Could not connect to the '%s' service: %s\n",
__func__, __LINE__, buf, strerror(errno));
close(fd);
return -errno;
}
return fd;
}
static int
qemud_channel_send(int pipe, const void* msg, int size)
{
char header[5];
if (size < 0) {
size = strlen(msg);
}
if (size == 0) {
return 0;
}
snprintf(header, sizeof(header), "%04x", size);
if (write(pipe, header, 4) < 0) {
return -errno;
}
if (write(pipe, msg, size) < 0) {
return -errno;
}
return size;
}
static int
qemud_channel_recv(int pipe, void* msg, int maxsize)
{
char header[5];
int size;
if (read(pipe, header, 4) < 0) {
return -errno;
}
header[4] = 0;
if (sscanf(header, "%04x", &size) != 1) {
return -errno;
}
if (size > maxsize) {
return -errno;
}
if (read(pipe, msg, size) < 0) {
return -errno;
}
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
****************************************************************************/
int main(void)
{
int qemud_fd;
/* try to connect to the qemud service */
int tries = MAX_TRIES;
while (true) {
qemud_fd = qemu_pipe_open_ns("qemud", "boot-properties", O_RDWR);
if (qemud_fd >= 0)
break;
if (--tries <= 0) {
fprintf(stderr,
"Could not connect after too many tries. Aborting\n");
return EXIT_FAILURE;
}
fprintf(stderr, "waiting 1s to wait for qemud.\n");
sleep(1);
}
fprintf(stderr, "connected to \"boot-properties\" qemud service.\n");
/* send the 'list' command to the service */
if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
fprintf(stderr,
"could not send command to \"boot-properties\" service\n");
return EXIT_FAILURE;
}
/* read each system property as a single line from the service,
* until exhaustion.
*/
while (true) {
char* prop_key;
char* prop_value;
char temp[BUFF_SIZE];
int len = qemud_channel_recv(qemud_fd, temp, sizeof(temp) - 1);
/* lone NUL-byte signals end of properties */
if (len < 0 || len > (BUFF_SIZE - 1) || !temp[0]) {
break;
}
temp[len] = '\0'; /* zero-terminate string */
/* separate propery name from value */
prop_key = temp;
prop_value = strchr(temp, '=');
if (!prop_value) {
continue;
}
*prop_value = '\0';
++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;
}
}
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;
}

624
kvdb/server.c Normal file
View File

@ -0,0 +1,624 @@
/*
* Copyright (C) 2020 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 <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>
#include <sys/un.h>
#include <kvdb.h>
#include "internal.h"
#if defined(CONFIG_NET_LOCAL) && defined(CONFIG_NET_RPMSG)
#define KVFD_LOCAL 0
#define KVFD_REMOTE 1
#define KVFD_COUNT 2
#else
#define KVFD_LOCAL 0
#define KVFD_REMOTE 0
#define KVFD_COUNT 1
#endif
#define KVFD_MAX 8
typedef struct kvdb_monitor {
int fd;
LIST_ENTRY(kvdb_monitor)
entry;
char key[0];
} kvdb_monitor;
typedef LIST_HEAD(kvdb_monitor_head, kvdb_monitor) kvdb_monitor_head;
typedef struct kvdb_server {
struct kvdb* kvdb;
int fd[KVFD_COUNT];
int efd;
bool running;
kvdb_monitor_head head;
} kvdb_server;
/* Open a monitor channel, add the [key, fd] pair to the monitor list and
* add the pollfd to the pollfd array.
*/
static int kvdb_monitor_open(kvdb_server* server, int fd, const char* key,
size_t key_len)
{
/* Malloc monitor element to store [key, fd] pair */
kvdb_monitor* mon = zalloc(sizeof(kvdb_monitor) + key_len);
if (mon == NULL) {
return -ENOMEM;
}
/* Add the monitor fd to the epoll */
struct epoll_event ev = {
.data.ptr = &mon->fd,
.events = EPOLLIN
};
int ret = epoll_ctl(server->efd, EPOLL_CTL_ADD, fd, &ev);
if (ret < 0) {
free(mon);
return ret;
}
/* Add the [key, fd] pair to the monitor list */
mon->fd = fd;
strcpy(mon->key, key);
LIST_INSERT_HEAD(&server->head, mon, entry);
return 0;
}
/* Close the monitor fd, remove the fd from the monitor list and empty
* corresponding pollfd.
*/
static void kvdb_monitor_close(kvdb_server* server, struct epoll_event* ev)
{
kvdb_monitor* mon = (kvdb_monitor*)ev->data.ptr;
/* Close the monitor fd and delete it from epoll */
epoll_ctl(server->efd, EPOLL_CTL_DEL, mon->fd, NULL);
close(mon->fd);
/* Remove the element from the monitor list */
LIST_REMOVE(mon, entry);
free(mon);
}
/* Notify the client the value changed (updated or deleted) */
static void kvdb_monitor_notify(kvdb_server* server, const char* key, const void* value, size_t val_len)
{
size_t key_len = strlen(key) + 1;
/* value != NULL
*---------------------------------*
| 1 | 1 | key_len |val_len|
|---------------------------------|
|key_len|val_len|[key'\0']|[value]|
*---------------------------------*
* value == NULL
*-------------------------*
| 1 | 1 | key_len |
|-------------------------|
|key_len| 0 |[key'\0']|
*-------------------------*/
char cmd[2] = { key_len, val_len };
struct iovec iov[3] = {
{ .iov_base = cmd, .iov_len = 2 },
{ .iov_base = (char*)key, .iov_len = key_len },
{ .iov_base = (char*)value, .iov_len = val_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = value ? 3 : 2;
kvdb_monitor* mon;
kvdb_monitor* tmp;
LIST_FOREACH_SAFE(mon, &server->head, entry, tmp)
{
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);
epoll_ctl(server->efd, EPOLL_CTL_DEL, mon->fd, NULL);
close(mon->fd);
free(mon);
}
}
}
static bool kvdb_is_comment(const char* line)
{
size_t i = strspn(line, " \t\r\n");
return line[i] == '\0' || line[i] == '#';
}
/****************************************************************************
* Network Functions
****************************************************************************/
static int kvdb_load(struct kvdb* kvdb, const char* src, bool force)
{
char* tmpb;
const char* path;
const char* sep;
int retry = 20;
char* buf = malloc(PROP_MSG_MAX);
if (buf == NULL) {
KVERR("malloc failed\n");
return -ENOMEM;
}
tmpb = malloc(PATH_MAX);
if (tmpb == NULL) {
KVERR("malloc failed\n");
free(buf);
return -ENOMEM;
}
path = tmpb;
while (*src) {
sep = strchr(src, ';');
if (sep) {
strlcpy(tmpb, src, MIN(PATH_MAX, sep - src + 1));
src = sep + 1;
} else {
path = src;
src += strlen(src);
}
/* Wait filesystem mount success */
while (access(path, 0) < 0 && retry-- > 0)
usleep(1000);
FILE* f = fopen(path, "re");
if (!f) {
KVERR("kvdb open:%s failed, errno:%d\n", path, errno);
continue;
}
while (fgets(buf, PROP_MSG_MAX, f)) {
if (kvdb_is_comment(buf))
continue;
char* tmp;
char* key = strtok_r(buf, "=", &tmp);
char* value = strtok_r(NULL, "\n", &tmp);
if (!key || !value)
continue;
size_t key_len = strlen(key) + 1;
if (!force && kvdb_get(kvdb, key, key_len, NULL, 0) >= 0)
continue;
kvdb_set(kvdb, key, key_len, value, strlen(value) + 1, true);
}
fclose(f);
}
kvdb_commit(kvdb);
free(tmpb);
free(buf);
return 0;
}
static int kvdb_bind(int fd[])
{
const int family[] = {
#ifdef CONFIG_NET_LOCAL
[KVFD_LOCAL] = AF_UNIX,
#endif
#ifdef CONFIG_NET_RPMSG
[KVFD_REMOTE] = AF_RPMSG,
#endif
};
#ifdef CONFIG_NET_LOCAL
const struct sockaddr_un addr0 = {
.sun_family = AF_UNIX,
.sun_path = PROP_SERVER_PATH,
};
#endif
#ifdef CONFIG_NET_RPMSG
const struct sockaddr_rpmsg addr1 = {
.rp_family = AF_RPMSG,
.rp_cpu = "",
.rp_name = PROP_SERVER_PATH,
};
#endif
const struct sockaddr* addr[] = {
#ifdef CONFIG_NET_LOCAL
[KVFD_LOCAL] = (const struct sockaddr*)&addr0,
#endif
#ifdef CONFIG_NET_RPMSG
[KVFD_REMOTE] = (const struct sockaddr*)&addr1,
#endif
};
const socklen_t addrlen[] = {
#ifdef CONFIG_NET_LOCAL
[KVFD_LOCAL] = sizeof(struct sockaddr_un),
#endif
#ifdef CONFIG_NET_RPMSG
[KVFD_REMOTE] = sizeof(struct sockaddr_rpmsg),
#endif
};
memset(fd, 0, sizeof(*fd) * KVFD_COUNT);
for (int i = 0; i < KVFD_COUNT; i++) {
fd[i] = socket(family[i], SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd[i] < 0)
continue;
int ret = bind(fd[i], addr[i], addrlen[i]);
if (ret < 0)
return ret;
ret = listen(fd[i], CONFIG_KVDB_BACKLOG_CONNS);
if (ret < 0)
return ret;
}
return 0;
}
static void kvdb_unbind(int fd[])
{
for (int i = 0; i < KVFD_COUNT; i++)
if (fd[i] > 0)
close(fd[i]);
}
#ifdef CONFIG_KVDB_DUMPLIST
static void kvdb_list_consume(const char* key, const void* value, size_t val_len, void* cookie)
{
size_t key_len = strlen(key) + 1;
char cmd[2] = {
key_len, val_len
};
struct iovec iov[3] = {
{ .iov_base = cmd, .iov_len = 2 },
{ .iov_base = (char*)key, .iov_len = key_len },
{ .iov_base = (char*)value, .iov_len = val_len },
};
struct msghdr msg = { 0 };
msg.msg_iov = iov;
msg.msg_iovlen = 3;
int fd = (intptr_t)cookie;
sendmsg(fd, &msg, 0);
}
#endif
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)
return ret;
if (ret == 0)
return -ENODATA;
offset += ret;
}
return len;
}
static bool kvdb_client(kvdb_server* server, int fd)
{
bool dirty = false;
ssize_t len;
char* msg;
#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
msg = malloc(PROP_MSG_MAX);
if (msg == NULL) {
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)
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)
break;
const char* key = msg + 2;
len = kvdb_recv(fd, msg, len, end_pos);
if (len > 0) {
int32_t err = kvdb_delete(server->kvdb, key, key_len);
if (err >= 0) {
dirty = true;
kvdb_monitor_notify(server, key, NULL, 0);
}
send(fd, &err, 4, 0);
}
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;
if (end_pos >= PROP_MSG_MAX)
break;
const char* key = msg + 3;
char value[PROP_VALUE_MAX];
len = kvdb_recv(fd, msg, len, end_pos);
if (len > 0) {
len = kvdb_get(server->kvdb, key, key_len, value, val_len);
if (len > 0)
send(fd, value, len, 0);
}
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;
if (end_pos >= PROP_MSG_MAX)
break;
const char* key = msg + 3;
const char* value = key + key_len;
len = kvdb_recv(fd, msg, len, end_pos);
if (len > 0) {
int32_t err = kvdb_set(server->kvdb, key, key_len, value, val_len, false);
if (err >= 0) {
dirty = true;
kvdb_monitor_notify(server, key, value, val_len);
}
send(fd, &err, 4, 0);
}
break;
}
#ifdef CONFIG_KVDB_DUMPLIST
case 'L': {
kvdb_list(server->kvdb, kvdb_list_consume, (void*)(uintptr_t)fd);
send(fd, "\0", 2, 0); /* terminator */
break;
}
#endif
case 'C': {
int ret = kvdb_commit(server->kvdb);
send(fd, &ret, sizeof(ret), 0);
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);
}
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;
if (end_pos >= PROP_MSG_MAX)
break;
const char* key = msg + 2;
len = kvdb_recv(fd, msg, len, end_pos);
if (len < 0 || key[key_len - 1]) {
break;
}
if (len > 0) {
int32_t err = kvdb_monitor_open(server, fd, key, key_len);
send(fd, &err, 4, 0);
}
/* Direct return, not close the monitor fd */
free(msg);
return false;
}
case 'E': {
int ret = 0;
server->running = false;
kvdb_uninit(server->kvdb);
send(fd, &ret, sizeof(ret), 0);
break;
}
}
out:
free(msg);
close(fd); /* done, close client socket */
return dirty;
}
static void kvdb_loop(kvdb_server* server)
{
struct epoll_event evs[KVFD_MAX];
struct timespec ts;
server->efd = epoll_create(KVFD_MAX);
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) {
close(server->efd);
return;
}
}
}
time_t next = 0;
server->running = true;
while (server->running) {
int timeout = -1;
/* commit the change after timeout */
if (next) {
clock_gettime(CLOCK_MONOTONIC, &ts);
timeout = (int)(next - ts.tv_sec);
if (timeout <= 0) {
kvdb_commit(server->kvdb);
timeout = -1;
next = 0;
} else
timeout *= 1000;
}
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)
if (fd != server->fd[0] && fd != server->fd[1]) {
#else
if (fd != server->fd[0]) {
#endif
if ((evs[i].events & EPOLLHUP) != 0) {
kvdb_monitor_close(server, &evs[i]);
}
continue;
}
if ((evs[i].events & EPOLLIN) == 0)
continue;
int newfd = accept(fd, NULL, NULL);
if (newfd < 0)
continue;
/* is database changed? */
if (kvdb_client(server, newfd) && next == 0) {
clock_gettime(CLOCK_MONOTONIC, &ts);
next = ts.tv_sec + CONFIG_KVDB_COMMIT_INTERVAL;
if (next == 0)
next++; /* ensure no zero */
}
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: main
*
* Description:
* Main entry point. Listens for UNIX domain socket connection and perform
* corresponding database operations.
*
****************************************************************************/
int main(int argc, char* argv[])
{
UNUSED(argc);
UNUSED(argv);
kvdb_server server = {
.head = LIST_HEAD_INITIALIZER(),
};
int ret = kvdb_bind(server.fd);
if (ret < 0)
goto out;
ret = kvdb_init(&server.kvdb);
if (ret < 0)
goto out;
kvdb_load(server.kvdb, CONFIG_KVDB_SOURCE_PATH, false);
kvdb_loop(&server);
out:
kvdb_unbind(server.fd);
return -ret;
}

42
kvdb/setprop.c Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2020 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 <stdio.h>
#include <string.h>
#include <kvdb.h>
int main(int argc, char* argv[])
{
int ret = 0;
if (argc == 3)
ret = -property_set(argv[1], argv[2]);
else if (argc == 2 && strncmp(argv[1], "-h", 3))
ret = -property_delete(argv[1]);
else
printf("Usage: %s <key> [value]\n", argv[0]);
if (ret > 0)
printf("Error: %s\n", strerror(ret));
else {
ret = -property_commit();
if (ret > 0)
printf("Error: commit %s\n", strerror(ret));
}
return ret;
}

135
kvdb/system_properties.c Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2023 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 <kvdb.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/system_properties.h>
struct system_property_foreach_cookie {
void* __cookie;
void (*__callback)(const prop_info* __pi, void* __cookie);
};
static uint32_t __system_property_serial_num = 0;
/*
* Sets system property `name` to `value`, creating the system property if it doesn't already exist.
*/
int __system_property_set(const char* __name, const char* __value)
{
int ret = property_set(__name, __value);
if (ret >= 0)
__system_property_serial_num++;
return ret;
}
/*
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
* Use __system_property_read_callback to query the current value.
*
* Property lookup is expensive, so it can be useful to cache the result of this function.
*/
const prop_info* __system_property_find(const char* __name)
{
int ret = property_get(__name, NULL, NULL);
if (ret < 0)
return NULL;
return (const prop_info*)__name;
}
/*
* Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
*/
void __system_property_read_callback(const prop_info* __pi,
void (*__callback)(void* __cookie, const char* __name, const char* __value, uint32_t __serial),
void* __cookie)
{
char value[PROP_VALUE_MAX];
if (__callback == NULL)
return;
int ret = property_get((const char*)__pi, value, NULL);
if (ret < 0)
return;
__callback(__cookie, (const char*)__pi, value, __system_property_serial_num);
}
/*
* used by __system_property_foreach() to pass to property_list.
*/
static void __system_property_foreach_callback(const char* key, const char* value, void* cookie)
{
struct system_property_foreach_cookie* pcookie = cookie;
pcookie->__callback((const prop_info*)key, pcookie->__cookie);
}
/*
* Iterates over each system property and invokes the provided callback.
* Use __system_property_read_callback() to read property values.
*
* This function is mainly for inspecting and debugging the property system.
*/
int __system_property_foreach(void (*__callback)(const prop_info* __pi, void* __cookie), void* __cookie)
{
struct system_property_foreach_cookie cookie = {
.__cookie = __cookie,
.__callback = __callback};
return property_list(__system_property_foreach_callback, &cookie);
}
/*
* Waits for the system property `pi` to be updated past `old_serial`, with an optional timeout.
* If `pi` is NULL, it waits for the global serial number.
* If the serial is unknown, pass 0.
*
* Returns true if updated within the timeout, false if the call times out.
*/
bool __system_property_wait(const prop_info* __pi, uint32_t __old_serial, uint32_t* __new_serial_ptr, const struct timespec* __relative_timeout)
{
int timems = __relative_timeout->tv_sec * 1000 + __relative_timeout->tv_nsec / 1000000;
int ret = property_wait(__pi ? (const char*)__pi : "*", NULL, NULL, 0, timems);
if (ret >= 0) {
if (__new_serial_ptr)
*__new_serial_ptr = __system_property_serial_num;
return true;
}
return false;
}
int __system_property_read(const prop_info* __pi, char* __name, char* __value)
{
strlcpy(__name, (const char*)__pi, PROP_NAME_MAX);
return property_get(__name, __value, NULL);
}
int __system_property_get(const char* __name, char* __value)
{
return property_get(__name, __value, NULL);
}

163
kvdb/unqlite.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2020 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 <stdio.h>
#include <stdlib.h>
#include <kvdb.h>
#include <unqlite.h>
#include "internal.h"
typedef struct kvdb_consume_data {
kvdb_consume consume;
void* cookie;
unqlite_kv_cursor* cur;
const char* key;
size_t key_len;
} kvdb_consume_data;
struct kvdb {
unqlite* db;
};
/****************************************************************************
* Database Functions
****************************************************************************/
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;
}
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);
return ret;
}
if (val_size <= 0)
return -EINVAL;
return val_size;
}
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;
}
static int kvdb_list_value(const void* value, unsigned int len, void* arg)
{
kvdb_consume_data* data = arg;
data->consume(data->key, value, len, data->cookie);
return 0;
}
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;
}
int kvdb_persist_list(struct kvdb* kvdb, kvdb_consume consume, void* cookie)
{
unqlite_kv_cursor* cur = NULL;
unqlite_kv_cursor_init(kvdb->db, &cur);
kvdb_consume_data data = {
.consume = consume,
.cookie = cookie,
.cur = cur,
};
unqlite_kv_cursor_first_entry(cur);
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;
}
unqlite_kv_cursor_next_entry(cur);
}
unqlite_kv_cursor_release(kvdb->db, cur);
return 0;
}
int kvdb_persist_commit(struct kvdb* kvdb)
{
int ret = unqlite_commit(kvdb->db);
if (ret < 0) {
KVERR("commit db:%p error %d!\n", kvdb->db, ret);
}
return ret;
}
void kvdb_persist_uninit(struct kvdb* kvdb)
{
if (kvdb != NULL) {
unqlite_close(kvdb->db);
free(kvdb);
}
}
int kvdb_persist_init(struct kvdb** kvdb)
{
int ret;
*kvdb = zalloc(sizeof(struct kvdb));
if (*kvdb == NULL)
return -ENOMEM;
/* open database */
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);
free(*kvdb);
}
return ret;
}

500
log/log_write.c Normal file
View File

@ -0,0 +1,500 @@
/*
* Copyright (C) 2023 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/streams.h>
#include <debug.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <android/log.h>
#include <android/set_abort_message.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define LOG_BUF_SIZE 256
/****************************************************************************
* Private Data
****************************************************************************/
static const int g_logprimap[ANDROID_LOG_SILENT + 1] = {
LOG_DEBUG, /* ANDROID_LOG_UNKNOWN */
LOG_DEBUG, /* ANDROID_LOG_DEFAULT */
LOG_DEBUG, /* ANDROID_LOG_VERBOSE */
LOG_DEBUG, /* ANDROID_LOG_DEBUG */
LOG_INFO, /* ANDROID_LOG_INFO */
LOG_WARNING, /* ANDROID_LOG_WARN */
LOG_ERR, /* ANDROID_LOG_ERROR */
LOG_CRIT, /* ANDROID_LOG_FATAL */
LOG_DEBUG, /* ANDROID_LOG_SILENT */
};
static __android_logger_function g_logger_function = __android_log_logd_logger;
static __android_aborter_function g_aborter_function = __android_log_default_aborter;
/****************************************************************************
* Private Functions
****************************************************************************/
/**
* Call get the default tag, if not set the default tag before, return "nullptr".
*/
static const char* __android_log_get_default_tag(void)
{
char* envtag = getenv("ANDROID_LOG_DEFAULT_TAG");
if (envtag == NULL) {
return getprogname();
}
return envtag;
}
/**
* Call __android_log_write_log_message() with a large buffer to support pass the message to user set
* logger
*/
static void __android_log_write_log_message_buf(int bufID, int prio, const char* tag, const char* fmt, va_list ap)
{
char buf[LOG_BUF_SIZE];
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
struct __android_log_message log_message = {
sizeof(struct __android_log_message), bufID, prio, tag, NULL, 0, buf
};
__android_log_write_log_message(&log_message);
}
/**
* Writes a formatted string to log buffer `id`,
* with priority `prio` and tag `tag`.
*
* 1 is returned on success. On failure, a negated errno value is
* returned.
*/
static int __android_log_buf_vprint(int bufID, int prio, const char* tag, const char* fmt, va_list ap)
{
if (tag == NULL) {
tag = __android_log_get_default_tag();
}
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
return -EPERM;
}
if (g_logger_function == __android_log_logd_logger) {
struct va_format vaf;
#ifdef va_copy
va_list copy;
va_copy(copy, ap);
vaf.fmt = fmt;
vaf.va = &copy;
#else
vaf.fmt = fmt;
vaf.va = &ap;
#endif
syslog(g_logprimap[prio], "[%s] %pV\n", tag, &vaf);
#ifdef va_copy
va_end(copy);
#endif
} else {
__android_log_write_log_message_buf(bufID, prio, tag, fmt, ap);
}
return 1;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/**
* Writes the constant string `text` to the log, with priority `prio` and tag
* `tag`.
*/
int __android_log_write(int prio, const char* tag, const char* text)
{
return __android_log_buf_write(LOG_ID_MAIN, prio, tag, text);
}
/**
* Writes a formatted string to the log, with priority `prio` and tag `tag`.
* The details of formatting are the same as for
* [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*/
int __android_log_print(int prio, const char* tag, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = __android_log_vprint(prio, tag, fmt, ap);
va_end(ap);
return ret;
}
/**
* Equivalent to `__android_log_print`, but taking a `va_list`.
* (If `__android_log_print` is like `printf`, this is like `vprintf`.)
*/
int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
{
return __android_log_buf_vprint(LOG_ID_MAIN, prio, tag, fmt, ap);
}
/**
* Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
* stderr, before calling
* [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
*
* If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
* `Assertion failed: %s` is used with `cond` as the string argument.
* If both `fmt` and `cond` are null, a default string is provided.
*
* Most callers should use
* [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
* `&lt;assert.h&gt;` instead, or the `__assert` and `__assert2` functions
* provided by bionic if more control is needed. They support automatically
* including the source filename and line number more conveniently than this
* function.
*/
void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...)
{
if (fmt) {
va_list ap;
va_start(ap, fmt);
__android_log_vprint(ANDROID_LOG_FATAL, tag, fmt, ap);
va_end(ap);
} else {
/* Msg not provided, log condition. N.B. Do not use cond directly as
* format string as it could contain spurious '%' syntax (e.g.
* "%d" in "blocks%devs == 0").
*/
if (cond) {
__android_log_print(ANDROID_LOG_FATAL, tag, "Assertion failed: %s\n", cond);
} else {
__android_log_print(ANDROID_LOG_FATAL, tag, "Unspecified assertion failed\n");
}
}
__android_log_call_aborter(tag);
/* noreturn function */
while (1)
;
}
/**
* Writes the constant string `text` to the log buffer `id`,
* with priority `prio` and tag `tag`.
*
* Apps should use __android_log_write() instead.
*/
int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text)
{
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
return -EPERM;
}
struct __android_log_message log_message = {
sizeof(struct __android_log_message), bufID, prio, tag, NULL, 0, text
};
__android_log_write_log_message(&log_message);
return 1;
}
/**
* Writes a formatted string to log buffer `id`,
* with priority `prio` and tag `tag`.
* The details of formatting are the same as for
* [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
*
* Apps should use __android_log_print() instead.
*/
int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = __android_log_buf_vprint(bufID, prio, tag, fmt, ap);
va_end(ap);
return ret;
}
/**
* Writes the log message specified by log_message. log_message includes additional file name and
* line number information that a logger may use. log_message is versioned for backwards
* compatibility.
* This assumes that loggability has already been checked through __android_log_is_loggable().
* Higher level logging libraries, such as libbase, first check loggability, then format their
* buffers, then pass the message to liblog via this function, and therefore we do not want to
* duplicate the loggability check here.
*
* @param log_message the log message itself, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_write_log_message(struct __android_log_message* log_message)
{
if (log_message->tag == NULL) {
log_message->tag = __android_log_get_default_tag();
}
if (log_message->priority == ANDROID_LOG_FATAL) {
android_set_abort_message(log_message->message);
}
g_logger_function(log_message);
}
/**
* Sets a user defined logger function. All log messages sent to liblog will be set to the
* function pointer specified by logger for processing. It is not expected that log messages are
* already terminated with a new line. This function should add new lines if required for line
* separation.
*
* @param logger the new function that will handle log messages.
*
* Available since API level 30.
*/
void __android_log_set_logger(__android_logger_function logger)
{
g_logger_function = logger;
}
/**
* Writes the log message to logd. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on a device.
*
* @param log_message the log message to write, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_logd_logger(const struct __android_log_message* log_message)
{
int32_t priority = log_message->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : log_message->priority;
if (log_message->file != NULL) {
syslog(g_logprimap[priority], "[%s %s:%" PRIu32 "] %s\n", log_message->tag,
log_message->file, log_message->line, log_message->message);
} else {
syslog(g_logprimap[priority], "[%s] %s\n", log_message->tag,
log_message->message);
}
}
/**
* Writes the log message to stderr. This is an __android_logger_function and can be provided to
* __android_log_set_logger(). It is the default logger when running liblog on host.
*
* @param log_message the log message to write, see __android_log_message.
*
* Available since API level 30.
*/
void __android_log_stderr_logger(const struct __android_log_message* log_message)
{
if (!__android_log_is_loggable(log_message->priority, NULL, ANDROID_LOG_VERBOSE)) {
return;
}
struct tm now;
time_t t = time(NULL);
localtime_r(&t, &now);
char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
static const char log_characters[ANDROID_LOG_SILENT + 1] = "XXVDIWEF";
int32_t priority = log_message->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : log_message->priority;
if (log_message->file != NULL) {
fprintf(stderr, "%s %c %s %5d %5d %s:%" PRIu32 "] %s\n",
log_message->tag, log_characters[priority], timestamp, getpid(), gettid(),
log_message->file, log_message->line, log_message->message);
} else {
fprintf(stderr, "%s %c %s %5d %5d] %s\n",
log_message->tag, log_characters[priority], timestamp, getpid(), gettid(),
log_message->message);
}
fflush(stderr);
}
/**
* Sets a user defined aborter function that is called for __android_log_assert() failures. This
* user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
* required to.
*
* @param aborter the new aborter function, see __android_aborter_function.
*
* Available since API level 30.
*/
void __android_log_set_aborter(__android_aborter_function aborter)
{
g_aborter_function = aborter;
}
/**
* Calls the stored aborter function. This allows for other logging libraries to use the same
* aborter function by calling this function in liblog.
*
* @param abort_message an additional message supplied when aborting, for example this is used to
* call android_set_abort_message() in __android_log_default_aborter().
*
* Available since API level 30.
*/
void __android_log_call_aborter(const char* abort_message)
{
g_aborter_function(abort_message);
}
/**
* Sets android_set_abort_message() on device then aborts(). This is the default aborter.
*
* @param abort_message an additional message supplied when aborting. This functions calls
* android_set_abort_message() with its contents.
*
* Available since API level 30.
*/
void __android_log_default_aborter(const char* abort_message)
{
android_set_abort_message(abort_message);
abort();
}
/**
* Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
* __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
* be printed. A non-zero result indicates yes, zero indicates false.
*
* If both a priority for a tag and a minimum priority are set by
* __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
* minimum priority needed to log. If only one is set, then that value is used to determine the
* minimum priority needed. If none are set, then default_priority is used.
*
* @param prio the priority to test, takes android_LogPriority values.
* @param tag the tag to test.
* @param default_prio the default priority to use if no properties or minimum priority are set.
* @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
*
* Available since API level 30.
*/
int __android_log_is_loggable(int prio, const char* tag, int default_prio)
{
int minimum_log_priority = __android_log_get_minimum_priority();
if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
return prio >= minimum_log_priority;
} else {
return prio >= default_prio;
}
}
/**
* Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
* __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
* be printed. A non-zero result indicates yes, zero indicates false.
*
* If both a priority for a tag and a minimum priority are set by
* __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
* minimum priority needed to log. If only one is set, then that value is used to determine the
* minimum priority needed. If none are set, then default_priority is used.
*
* @param prio the priority to test, takes android_LogPriority values.
* @param tag the tag to test.
* @param len the length of the tag.
* @param default_prio the default priority to use if no properties or minimum priority are set.
* @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
*
* Available since API level 30.
*/
int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
{
return __android_log_is_loggable(prio, tag, default_prio);
}
/**
* Sets the minimum priority that will be logged for this process.
*
* @param priority the new minimum priority to set, takes android_LogPriority values.
* @return the previous set minimum priority as android_LogPriority values, or
* ANDROID_LOG_DEFAULT if none was set.
*
* Available since API level 30.
*/
int32_t __android_log_set_minimum_priority(int32_t priority)
{
char buffer[sizeof(int32_t) * 8 + 1];
int32_t old_minimum_log_priority = __android_log_get_minimum_priority();
priority = priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : priority;
setenv("ANDROID_LOG_MIN_PRIORITY", itoa(priority, buffer, 10), true);
return old_minimum_log_priority;
}
/**
* Gets the minimum priority that will be logged for this process. If none has been set by a
* previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
*
* @return the current minimum priority as android_LogPriority values, or
* ANDROID_LOG_DEFAULT if none is set.
*
* Available since API level 30.
*/
int32_t __android_log_get_minimum_priority(void)
{
char* envprio = getenv("ANDROID_LOG_MIN_PRIORITY");
if (envprio == NULL) {
return ANDROID_LOG_DEFAULT;
}
return atoi(envprio);
}
/**
* Sets the default tag if no tag is provided when writing a log message. Defaults to
* getprogname(). This truncates tag to the maximum log message size, though appropriate tags
* should be much smaller.
*
* @param tag the new log tag.
*
* Available since API level 30.
*/
void __android_log_set_default_tag(const char* tag)
{
if (tag != NULL) {
setenv("ANDROID_LOG_DEFAULT_TAG", tag, true);
}
}
int __android_log_error_write(int tag, const char* subTag, int32_t uid,
const char* data, uint32_t dataLen)
{
__android_log_print(ANDROID_LOG_ERROR, subTag,
"tag: %d uid: %" PRId32 " data: %s\n",
tag, uid, data);
return 0;
}

33
log/set_abort_message.c Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <syslog.h>
#include <android/set_abort_message.h>
/****************************************************************************
* Public Functions
****************************************************************************/
void android_set_abort_message(const char* __msg)
{
syslog(LOG_ALERT, "Abort Message: %s", __msg);
}

178
trace/atrace.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright (C) 2020 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cutils/trace.h>
/****************************************************************************
* Private Types
****************************************************************************/
struct atrace_category {
uint64_t tag;
const char* name;
const char* help;
};
/****************************************************************************
* Private Data
****************************************************************************/
static const struct atrace_category category_list[] = {
{ ATRACE_TAG_NEVER, "never", "never output trace" },
{ ATRACE_TAG_ALWAYS, "always", "always output trace" },
{ ATRACE_TAG_GRAPHICS, "gfx", "graphics" },
{ ATRACE_TAG_INPUT, "input", "input" },
{ ATRACE_TAG_VIEW, "view", "view" },
{ ATRACE_TAG_WEBVIEW, "webview", "webview" },
{ ATRACE_TAG_WINDOW_MANAGER, "wm", "window_manager" },
{ ATRACE_TAG_ACTIVITY_MANAGER, "am", "activity_manager" },
{ ATRACE_TAG_SYNC_MANAGER, "sm", "sync_manager" },
{ ATRACE_TAG_AUDIO, "audio", "audio" },
{ ATRACE_TAG_VIDEO, "video", "video" },
{ ATRACE_TAG_CAMERA, "camera", "camera" },
{ ATRACE_TAG_HAL, "hal", "hal" },
{ ATRACE_TAG_APP, "app", "app" },
{ ATRACE_TAG_RESOURCES, "res", "resources" },
{ ATRACE_TAG_DALVIK, "dalvik", "dalvik" },
{ ATRACE_TAG_RS, "rs", "rs" },
{ ATRACE_TAG_BIONIC, "bionic", "bionic" },
{ ATRACE_TAG_POWER, "power", "power" },
{ ATRACE_TAG_PACKAGE_MANAGER, "pm", "package_manager" },
{ ATRACE_TAG_SYSTEM_SERVER, "ss", "system_server" },
{ ATRACE_TAG_DATABASE, "db", "database" },
{ ATRACE_TAG_NETWORK, "net", "network" },
{ ATRACE_TAG_ADB, "adb", "adb" },
{ ATRACE_TAG_VIBRATOR, "vibrator", "vibrator" },
{ ATRACE_TAG_AIDL, "aidl", "aidl" },
{ ATRACE_TAG_NNAPI, "nnapi", "nnapi" },
{ ATRACE_TAG_RRO, "rro", "rro" },
{ ATRACE_TAG_THERMAL, "thermal", "thermal" },
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* atrace_help
****************************************************************************/
static int atrace_help(const char* progname)
{
printf("Usage: %s [option] [categories...]\n"
"options include:\n"
" --list_categories\n"
" list the available tracing categories\n",
progname);
return 0;
}
/****************************************************************************
* atrace_list
*
* Description:
* List all available categories
*
****************************************************************************/
static int atrace_list(void)
{
int i;
printf("Available categories:\n");
for (i = 0; i < sizeof(category_list) / sizeof(category_list[0]); i++) {
printf("\t%s: %s\n", category_list[i].name, category_list[i].help);
}
return 0;
}
/****************************************************************************
* atrace_category
*
* Description:
* Update tracing tag
*
****************************************************************************/
static int atrace_category(int argc, char** argv)
{
int i;
int j;
uint64_t tag = 0;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "always") == 0) {
tag = UINT64_MAX;
} else if (strcmp(argv[i], "never") == 0) {
tag = 0ull;
} else {
for (j = 2; j < sizeof(category_list) / sizeof(category_list[0]); j++) {
if (strcmp(argv[i], category_list[j].name) == 0) {
tag |= category_list[j].tag;
break;
}
}
}
if (j == sizeof(category_list) / sizeof(category_list[0])) {
printf("Unknown category: %s", argv[i]);
return -EINVAL;
}
}
atrace_enabled_tags = tag;
printf("Android tracing enabled with tag: %#" PRIx64 "\n", tag);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: main
*
* Description:
* This is the main entry point for the atrace command.
*
****************************************************************************/
int main(int argc, char** argv)
{
int ret;
if (argc < 2) {
atrace_help(argv[0]);
return EXIT_FAILURE;
}
if (strcmp(argv[1], "--list_categories") == 0) {
ret = atrace_list();
} else {
ret = atrace_category(argc, argv);
}
return ret;
}

112
trace/trace.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2020 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.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <cutils/trace.h>
#include <nuttx/sched_note.h>
int atrace_marker_fd = -1;
uint64_t atrace_enabled_tags = ~0ull;
/****************************************************************************
* Public Functions
****************************************************************************/
uint64_t atrace_get_enabled_tags(void)
{
return atrace_enabled_tags;
}
void atrace_init(void)
{
}
void atrace_setup(void)
{
}
void atrace_update_tags(void)
{
}
void atrace_set_debuggable(bool debuggable)
{
}
void atrace_set_tracing_enabled(bool enabled)
{
}
void atrace_begin_body(const char* name)
{
sched_note_printf(NOTE_TAG_ALWAYS, "B|%d|%s", gettid(), name);
}
void atrace_end_body(void)
{
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, "S|%d|%s|%" PRId32, gettid(),
name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
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, "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)
{
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, "I|%d|%s", gettid(), name);
}
void atrace_instant_for_track_body(const char* track_name, const char* name)
{
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, "C|%d|%s|%" PRId32,
gettid(), name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
sched_note_printf(NOTE_TAG_ALWAYS, "C|%d|%s|%" PRId64, gettid(),
name, value);
}