Compare commits
18 Commits
dev
...
dev-backup
| Author | SHA1 | Date |
|---|---|---|
|
|
33b57ae7b6 | |
|
|
5ab09981ce | |
|
|
db3047f550 | |
|
|
319fa078ad | |
|
|
e5494311ba | |
|
|
2ccf67284d | |
|
|
67656912d8 | |
|
|
b0ddf494af | |
|
|
a44fb5a327 | |
|
|
168b12ef14 | |
|
|
6a96d1f18e | |
|
|
934dd070fa | |
|
|
171cb5f416 | |
|
|
eac77e5491 | |
|
|
ae9f5b50cf | |
|
|
79f5248b8c | |
|
|
362d791987 | |
|
|
4b6dd71a31 |
|
|
@ -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`。
|
||||
- 搜索 [现有问题](./)
|
||||
|
|
@ -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: |
|
||||
提交前请搜索 [现有功能需求](./)
|
||||
|
||||
|
|
@ -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 文档](../),但未找到问题的答案。
|
||||
- 已搜索 [现有问题](./)
|
||||
|
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: false
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
## 概要
|
||||
|
||||
*在此部分更新信息,说明更改的必要性、具体做了什么以及如何实现的,如果有新功能出现,请提供参考资料(依赖关系、类似问题和解决方案等)。*
|
||||
|
||||
## 影响
|
||||
|
||||
*在此部分更新信息(如适用),说明更改如何影响用户、构建过程、硬件、文档、安全性、兼容性等。*
|
||||
|
||||
## 测试
|
||||
|
||||
*在此部分更新信息,详细说明如何验证更改,使用什么主机进行构建(操作系统、CPU、编译器等),使用什么目标进行验证(架构、板子:配置等)。提供更改前后的构建和运行日志将非常有帮助。*
|
||||
|
|
@ -0,0 +1 @@
|
|||
* @xiaoxiang781216 @GUIDINGLI @huangcaihua-xm
|
||||
|
|
@ -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))
|
||||
|
||||
|
|
@ -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))
|
||||
|
|
@ -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))
|
||||
|
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: false
|
||||
|
|
@ -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.*
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# 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]
|
||||
|
||||
# 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/uv
|
||||
*.o
|
||||
Make.dep
|
||||
.depend
|
||||
.built
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
cc_defaults {
|
||||
name: "kvdb_defaults",
|
||||
|
||||
static_libs: [
|
||||
"libkvdb",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libkvdb",
|
||||
export_include_dirs: ["include"],
|
||||
|
||||
srcs: [
|
||||
"kvdb/common.c",
|
||||
"kvdb/system_properties.c",
|
||||
"kvdb/client.c",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-DCONFIG_KVDB_SERVER_CPUNAME=\"ap\"",
|
||||
"-fvisibility=hidden",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "likvdb_headers",
|
||||
export_include_dirs: ["include"],
|
||||
proprietary: true
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "kvset",
|
||||
srcs: ["kvdb/setprop.c"],
|
||||
defaults: ["kvdb_defaults"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "kvget",
|
||||
srcs: ["kvdb/getprop.c"],
|
||||
defaults: ["kvdb_defaults"],
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
#
|
||||
# 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_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)
|
||||
|
||||
if(CONFIG_SCHED_INSTRUMENTATION_DUMP)
|
||||
list(APPEND CSRCS trace/trace.c)
|
||||
endif()
|
||||
if(CONFIG_ANDROID_LIBBASE)
|
||||
list(APPEND CSRCS log/log_write.c log/set_abort_message.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ATRACE)
|
||||
nuttx_add_application(NAME atrace SRCS trace/atrace.c DEPENDS
|
||||
framework_utils)
|
||||
endif()
|
||||
|
||||
if(CONFIG_KVDB)
|
||||
if(CONFIG_KVDB_DIRECT)
|
||||
list(APPEND CSRCS kvdb/direct.c)
|
||||
else()
|
||||
list(APPEND CSRCS kvdb/client.c)
|
||||
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)
|
||||
endif()
|
||||
|
||||
target_sources(framework_utils PRIVATE ${CSRCS})
|
||||
target_include_directories(framework_utils PRIVATE ${INCDIR})
|
||||
target_compile_options(framework_utils PRIVATE ${CFLAGS})
|
||||
|
||||
endif()
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
#
|
||||
# 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 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
|
||||
|
||||
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"
|
||||
select MTD_CONFIG_NAMED
|
||||
depends on MTD_CONFIG_FAIL_SAFE
|
||||
---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"
|
||||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#
|
||||
# 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
|
||||
|
||||
ifneq ($(CONFIG_SCHED_INSTRUMENTATION_DUMP),)
|
||||
CSRCS += trace/trace.c
|
||||
endif
|
||||
|
||||
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_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
|
||||
|
||||
ASRCS := $(wildcard $(ASRCS))
|
||||
CSRCS := $(wildcard $(CSRCS))
|
||||
CXXSRCS := $(wildcard $(CXXSRCS))
|
||||
MAINSRC := $(wildcard $(MAINSRC))
|
||||
NOEXPORTSRCS = $(ASRCS)$(CSRCS)$(CXXSRCS)$(MAINSRC)
|
||||
|
||||
ifneq ($(NOEXPORTSRCS),)
|
||||
BIN := $(APPDIR)/staging/libutils.a
|
||||
endif
|
||||
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
# 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 |
|
||||
| -- | -- |
|
||||
| `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 `openvela`. |
|
||||
| `trace` | Provides a dotting tool for user-space programs. |
|
||||
|
||||
## Project Description
|
||||
|
||||
### 1 kvdb
|
||||
|
||||
#### Brief introduction
|
||||
|
||||
`kvdb` provides a set of local database read and write interfaces. The `API` design refers to the `properties` access specification of `Android`, and also provides command line tools to facilitate local quick debugging.
|
||||
|
||||
`kvdb` in `openvela` supports local persistent storage and cross-core calls (requires Unix domain socket and rpmsg socket support respectively). The key value that needs to be permanently stored in the file needs to start with `"persist."`.
|
||||
|
||||
`kvdb` underlying implementation includes three mechanisms:
|
||||
|
||||
1. Based on the open source `UnQLite` database, dependent on the database.
|
||||
|
||||
2. Based on `MTD CONFIG` (currently only used for nor flash).
|
||||
|
||||
3. The last one is based on `file` files.
|
||||
|
||||
> `kvdb` interface description: [frameworks/utils/include/kvdb.h](include/kvdb.h)
|
||||
|
||||
#### kvdb common configuration description
|
||||
|
||||
| kvdb configuration | Description |
|
||||
| -- | -- |
|
||||
| CONFIG_KVDB_PRIORITY | KVDB task priority, defaults to system default |
|
||||
| CONFIG_KVDB_STACKSIZE | KVDB stack space allocation, defaults to system default |
|
||||
| CONFIG_KVDB_SERVER | KVDB SERVER mode: indicates whether the current CPU is the main CPU for reading and writing files, if it is n, only KVDB on other CPUs is called |
|
||||
| CONFIG_KVDB_DIRECT | KVDB DIRECT mode: This mode can be used in scenarios where rpmsg socket is not required (no need for cross-core)<br>CONFIG_KVDB_DIRECT and CONFIG_KVDB_SERVER can only be selected from the two modes |
|
||||
| CONFIG_KVDB_COMMIT_INTERVAL | KVDB commit interval (seconds), default is 5 <br> KVDB has internal cache, and the data is actually written to the file only after committing. If the power is turned off before `CONFIG_KVDB_COMMIT_INTERVAL` time after committing the persist type kv, the data will not be actually written to the `persist.db` file. The shorter the `CONFIG_KVDB_COMMIT_INTERVAL` time is set, the more frequently `kvdb` writes the internal cache to the file, which will affect the system performance to a certain extent. |
|
||||
| CONFIG_KVDB_SOURCE_PATH | KVDB default value loading path, the default is `"/etc/build.prop"`, supports multiple paths, separated by `;`, and the KV value will be automatically loaded from this file every time the computer starts. |
|
||||
| CONFIG_KVDB_UNQLITE | Configure to use unqlite database to store kv |
|
||||
| CONFIG_KVDB_NVS | Configure to use nvs to store kv |
|
||||
| CONFIG_KVDB_FILE | Configure to use file to store kv |
|
||||
|
||||
> Only one of the three data storage `backend`s `CONFIG_KVDB_UNQLITE`, `CONFIG_KVDB_NVS`, and `CONFIG_KVDB_FILE` can be selected.
|
||||
|
||||
### 2 log
|
||||
|
||||
The log module itself is a wrapper layer, which encapsulates the `openvela log` system at the bottom layer. The encapsulated API is consistent with the `log API` in Android. When we port the `Android` application or framework to `openvela`, we do not need to provide our own `log` connection, and can directly use the current module.
|
||||
The following is the structure of the log module:
|
||||
|
||||
```log
|
||||
android log api
|
||||
|
|
||||
\|/
|
||||
log wrapper
|
||||
|
|
||||
\|/
|
||||
vela log impl
|
||||
```
|
||||
|
||||
### 3 trace
|
||||
|
||||
This module mainly contains the dot analysis tool for user space programs. We can implement dot analysis by manually inserting stubs in user programs.
|
||||
The atrace tool provided in trace is mainly used in conjunction with the dot analysis tool provided by the openvela system.
|
||||
|
||||
## Usage Guide
|
||||
|
||||
|
||||
### 1 kvdb
|
||||
|
||||
`kvdb` itself has multiple usage forms. We can integrate it directly in the code, or use it directly in `nsh` as a command line program.
|
||||
|
||||
#### 1.1 Example of direct integration in the code
|
||||
|
||||
The following is a demo of the interface provided by `kvdb` to monitor `key/value` changes. Two sets of APIs are provided for simple and complex scenarios:
|
||||
|
||||
1. Simple scenario: Only one `key` can be monitored.
|
||||
|
||||
```cpp
|
||||
int main(void)
|
||||
{
|
||||
char newkey[PROPERTY_KEY_MAX];
|
||||
char newvalue[PROPERTY_VALUE_MAX];
|
||||
int ret = property_wait("tsetkey", newkey, newvalue, -1);
|
||||
if (ret < 0)
|
||||
{
|
||||
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 scenarios: Supports `poll`, allowing users to freely monitor multiple `keys`.
|
||||
|
||||
```cpp
|
||||
int main(void)
|
||||
{
|
||||
struct pollfd fds[2];
|
||||
char newkey[PROPERTY_KEY_MAX];
|
||||
char newvalue[PROPERTY_VALUE_MAX];
|
||||
int fd1 = property_monitor_open("monitorkey*");
|
||||
int fd2 = property_monitor_open("testkey");
|
||||
|
||||
fds[0].fd = fd1;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = fd2;
|
||||
fds[1].events = POLLIN;
|
||||
int ret= poll(fds, 2, -1);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if ((fds[i].revents & POLLIN) == 0)
|
||||
continue;
|
||||
|
||||
ret = property_monitor_read(fds[i].fd, newkey, newvalue);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
printf("the new key: %s\n", newkey);
|
||||
printf("the new value: %s\n", newvalue);
|
||||
}
|
||||
|
||||
out:
|
||||
property_monitor_close(fd1);
|
||||
property_monitor_close(fd2);
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 Use in nsh as command line
|
||||
|
||||
KVDB provides two command line programs, `getprop` and `setprop`, for users to use. Users can use `getprop` and `setprop` to easily view existing KVs or set new KVs.
|
||||
|
||||
These two command lines are enabled by default after KVDB is enabled.
|
||||
- getprop: print out the set property
|
||||
- nsh> getprop: list all current `props`
|
||||
- nsh> getprop `key`: print out the `prop` corresponding to `key`
|
||||
- setprop: set or delete property
|
||||
- nsh> setprop `key`: delete the `prop` corresponding to `key`
|
||||
- nsh> setprop `key` `value`: save `key`:`value` to the database
|
||||
|
||||
Here are specific usage examples:
|
||||
|
||||
```log
|
||||
nsh> setprop name peter # add a key-value pair named name with a value of peter, which disappears when the power is off
|
||||
nsh> setprop persist.name1 peter1 # add a key-value pair named name1 with a value of peter1, which does not disappear when the power is off
|
||||
nsh> getprop # view all key-value pairs
|
||||
name: peter
|
||||
nsh> setprop name # delete a key-value pair named name
|
||||
nsh> getprop name
|
||||
```
|
||||
|
||||
|
||||
### 2 log
|
||||
|
||||
1. Enable `CONFIG_ANDROID_LIBBASE`.
|
||||
2. Use the standard Android log API to collect and print logs directly in the program.
|
||||
|
||||
```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;
|
||||
}
|
||||
```
|
||||
|
||||
### 3 trace
|
||||
|
||||
1. To enable the `CONFIG_SCHED_INSTRUMENTATION_DUMP` and `CONFIG_ATRACE` build options
|
||||
|
||||
2. Add the instrumentation point in the program:
|
||||
|
||||
```cpp
|
||||
// define the tag for tracing
|
||||
#define ATRACE_TAG ATRACE_TAG_ALWAYS
|
||||
#include <cutils/trace.h>
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
# Utils
|
||||
|
||||
[[English](./README.md) | [中文](./README_zh-cn.md)]
|
||||
|
||||
## 项目概览
|
||||
|
||||
当前目录下包含的主要是 framework 当中提供的一些常用工具实现。
|
||||
| 工具 | 工具简要描述 |
|
||||
| -- | -- |
|
||||
| `kvdb` | 基于本地数据库的`键值对`数据存取接口 |
|
||||
| `log` | 提供和 `Android` 平台兼容的 `Log API` 接口<br>用于在 `openvela` 当中直接使用 Android LOG API |
|
||||
| `trace` | 提供用于用户空间程序的打点工具 |
|
||||
|
||||
## 项目描述
|
||||
|
||||
### 1 kvdb
|
||||
|
||||
#### 简要介绍
|
||||
|
||||
`kvdb` 提供了一套本地数据库的读写接口, `API` 设计参考 `Android`的 `properties` 存取规范, 同时提供了命令行工具以方便本地快速调试。
|
||||
`openvela` 中的 `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)
|
||||
|
||||
#### 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` 只能三选一。
|
||||
|
||||
### 2 log
|
||||
|
||||
log 模块本身是一个 wrapper 层,底层将 `openvela log` 系统进行了封装,封装成的 API 是和 Android 当中的 `log API` 一致, 当我们将 `Android` 应用或者框架移植到 `openvela` 当中时, 不需要再提供自己的 `log` 对接,直接使用当前模块就可以了。
|
||||
以下是log模块的结构:
|
||||
|
||||
```log
|
||||
android log api
|
||||
|
|
||||
\|/
|
||||
log wrapper
|
||||
|
|
||||
\|/
|
||||
vela log impl
|
||||
```
|
||||
|
||||
### 3 trace
|
||||
|
||||
这个模块当中包含的主要是用于用户空间程序的打点工具,我们可以通过在用户程序当中手动插桩来实现打点分析,
|
||||
trace 当中提供的 atrace 工具主要是配合 openvela 系统提供的打点工具来使用的。
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 1 kvdb
|
||||
|
||||
`kvdb` 本身有多种使用形式,我们可以直接在代码当中集成,也可以直接在 `nsh` 当中以命令行程序的方式来使用。
|
||||
|
||||
#### 1.1 直接在代码当中集成的示例
|
||||
|
||||
以下是针对 `kvdb` 当中提供的监控 `key/value`变化的接口的 demo,针对简单和复杂场景,提供了两套 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;
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 在 nsh 当中以命令行的形式来使用
|
||||
|
||||
KVDB 提供了 `getprop` 和 `setprop` 两个命令行程序供用户使用,用户可以使用 `getprop` 和 `setprop` 方便地查看已存在的 KV 或是设置新的 KV。
|
||||
|
||||
这两个命令行在使能 KVDB 后默认开启。
|
||||
- getprop:打印出设置的 property
|
||||
- nsh> getprop:列出当前所有`props`
|
||||
- nsh> getprop `key`:打印出 `key` 对应的`prop`
|
||||
|
||||
- setprop:设置或者删除 property
|
||||
- nsh> setprop `key` : 删除 `key` 对应的`prop`
|
||||
- nsh> setprop `key` `value` :保存 `key`:`value`到数据库
|
||||
|
||||
下面是具体的使用示例:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### 2 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;
|
||||
}
|
||||
```
|
||||
|
||||
### 3 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 的时序图。
|
||||
|
|
@ -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
|
||||
* `<assert.h>` 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
|
||||
|
||||
/** @} */
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
static inline void atrace_async_for_track_begin(uint64_t tag, const char* track_name,
|
||||
const char* name, int32_t cookie) {
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_async_for_track_begin_body(const char*, const char*, int32_t);
|
||||
atrace_async_for_track_begin_body(track_name, name, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
static inline void atrace_async_for_track_end(uint64_t tag, const char* track_name,
|
||||
const char* name, int32_t cookie) {
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_async_for_track_end_body(const char*, const char*, int32_t);
|
||||
atrace_async_for_track_end_body(track_name, name, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
static inline void atrace_instant(uint64_t tag, const char* name) {
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_instant_body(const char*);
|
||||
atrace_instant_body(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
static inline void atrace_instant_for_track(uint64_t tag, const char* track_name,
|
||||
const char* name) {
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_instant_for_track_body(const char*, const char*);
|
||||
atrace_instant_for_track_body(track_name, name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
static inline void atrace_int(uint64_t tag, const char* name, int32_t value)
|
||||
{
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_int_body(const char*, int32_t);
|
||||
atrace_int_body(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
static inline void atrace_int64(uint64_t tag, const char* name, int64_t value)
|
||||
{
|
||||
if (atrace_is_tag_enabled(tag)) {
|
||||
void atrace_int64_body(const char*, int64_t);
|
||||
atrace_int64_body(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _LIBS_CUTILS_TRACE_H
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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 Reload default property value.
|
||||
* @return On success returns 0, -errno otherwise.
|
||||
*/
|
||||
int property_reload(void);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,831 @@
|
|||
/*
|
||||
* 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)
|
||||
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_reload
|
||||
*
|
||||
* Description:
|
||||
* Reload default property value
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* On success returns 0.
|
||||
* On failure returns -errno.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int property_reload(void)
|
||||
{
|
||||
int fd = property_connect();
|
||||
int ret;
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ret = send(fd, "R", 1, 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
/* in environment variable? */
|
||||
const char* env = getenv(key);
|
||||
if (env) {
|
||||
size_t len = strlen(env);
|
||||
if (len >= PROP_VALUE_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
if (value)
|
||||
memcpy(value, env, len + 1);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t ret = property_get_binary(key, value, PROP_VALUE_MAX);
|
||||
if (ret <= 0) {
|
||||
if (!default_value)
|
||||
return -EINVAL;
|
||||
size_t len = strlen(default_value);
|
||||
if (value)
|
||||
memcpy(value, default_value, len + 1);
|
||||
return len;
|
||||
}
|
||||
*(value + ret) = '\0';
|
||||
return strlen(value);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
char buf[PROP_VALUE_MAX];
|
||||
int len = property_get(key, buf, NULL);
|
||||
if (len == 1) {
|
||||
char ch = buf[0];
|
||||
if (ch == '0' || ch == 'n')
|
||||
return 0;
|
||||
else if (ch == '1' || ch == 'y')
|
||||
return 1;
|
||||
} else if (len > 1) {
|
||||
if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off"))
|
||||
return 0;
|
||||
else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on"))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return default_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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
char value[PROP_VALUE_MAX];
|
||||
if (property_get(key, value, NULL) < 0)
|
||||
return default_value;
|
||||
|
||||
errno = 0;
|
||||
char* end;
|
||||
int32_t ret = strtol(value, &end, 0);
|
||||
if (errno || *end || value == end)
|
||||
return default_value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
char value[PROP_VALUE_MAX];
|
||||
if (property_get(key, value, NULL) < 0)
|
||||
return default_value;
|
||||
|
||||
errno = 0;
|
||||
char* end;
|
||||
int64_t ret = strtoll(value, &end, 0);
|
||||
if (errno || *end || value == end)
|
||||
return default_value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -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_reload
|
||||
*
|
||||
* Description:
|
||||
* Reload default property value
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int property_reload(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: property_exit
|
||||
*
|
||||
* Description:
|
||||
* Exit Kvdb Server (Dummy Function)
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int property_exit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* 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 "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
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#ifdef CONFIG_KVDB_DUMPLIST
|
||||
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");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* 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 "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;
|
||||
}
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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 (property_set(prop_key, prop_value) < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
close(qemud_fd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,574 @@
|
|||
/*
|
||||
* 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 <netpacket/rpmsg.h>
|
||||
#include <sys/epoll.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;
|
||||
|
||||
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], SOMAXCONN);
|
||||
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': {
|
||||
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': {
|
||||
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': {
|
||||
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': {
|
||||
kvdb_load(server->kvdb, CONFIG_KVDB_SOURCE_PATH, true);
|
||||
break;
|
||||
}
|
||||
case 'M': {
|
||||
/* 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;
|
||||
#ifdef CONFIG_NET_RPMSG
|
||||
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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
return unqlite_kv_store(kvdb->db, key, key_len, value, val_len);
|
||||
}
|
||||
|
||||
ssize_t kvdb_persist_get(struct kvdb* kvdb, const char* key, size_t key_len, void* value, size_t val_len)
|
||||
{
|
||||
unqlite_int64 val_size = val_len;
|
||||
ssize_t ret = unqlite_kv_fetch(kvdb->db, key, key_len, value, &val_size);
|
||||
if (ret < 0)
|
||||
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)
|
||||
{
|
||||
return unqlite_kv_delete(kvdb->db, key, key_len);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
kvdb_consume_data* data = arg;
|
||||
data->key = value;
|
||||
data->key_len = len;
|
||||
return unqlite_kv_cursor_data_callback(data->cur, kvdb_list_value, data);
|
||||
}
|
||||
|
||||
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 */
|
||||
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)
|
||||
free(*kvdb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* 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 <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 = ©
|
||||
#else
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = ≈
|
||||
#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
|
||||
* `<assert.h>` 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
Loading…
Reference in New Issue