mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
resetprop: replace nanopb with quick-protobuf for persist
This commit is contained in:
parent
7826d7527f
commit
8d81bd0e33
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -16,9 +16,6 @@
|
|||||||
[submodule "xz"]
|
[submodule "xz"]
|
||||||
path = native/src/external/xz
|
path = native/src/external/xz
|
||||||
url = https://github.com/xz-mirror/xz.git
|
url = https://github.com/xz-mirror/xz.git
|
||||||
[submodule "nanopb"]
|
|
||||||
path = native/src/external/nanopb
|
|
||||||
url = https://github.com/nanopb/nanopb.git
|
|
||||||
[submodule "pcre"]
|
[submodule "pcre"]
|
||||||
path = native/src/external/pcre
|
path = native/src/external/pcre
|
||||||
url = https://android.googlesource.com/platform/external/pcre
|
url = https://android.googlesource.com/platform/external/pcre
|
||||||
|
@ -10,7 +10,6 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE := magisk
|
LOCAL_MODULE := magisk
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
libbase \
|
libbase \
|
||||||
libnanopb \
|
|
||||||
libsystemproperties \
|
libsystemproperties \
|
||||||
libphmap \
|
libphmap \
|
||||||
liblsplt \
|
liblsplt \
|
||||||
@ -28,7 +27,6 @@ LOCAL_SRC_FILES := \
|
|||||||
core/restorecon.cpp \
|
core/restorecon.cpp \
|
||||||
core/module.cpp \
|
core/module.cpp \
|
||||||
core/thread.cpp \
|
core/thread.cpp \
|
||||||
core/resetprop/persist.cpp \
|
|
||||||
core/resetprop/resetprop.cpp \
|
core/resetprop/resetprop.cpp \
|
||||||
core/core-rs.cpp \
|
core/core-rs.cpp \
|
||||||
core/su/su.cpp \
|
core/su/su.cpp \
|
||||||
@ -139,14 +137,13 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE := resetprop
|
LOCAL_MODULE := resetprop
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
libbase \
|
libbase \
|
||||||
libnanopb \
|
|
||||||
libsystemproperties \
|
libsystemproperties \
|
||||||
libmagisk-rs
|
libmagisk-rs
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
core/applet_stub.cpp \
|
core/applet_stub.cpp \
|
||||||
core/resetprop/resetprop.cpp \
|
core/resetprop/resetprop.cpp \
|
||||||
core/resetprop/persist.cpp
|
core/core-rs.cpp
|
||||||
|
|
||||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
2
native/src/Cargo.lock
generated
2
native/src/Cargo.lock
generated
@ -424,6 +424,8 @@ dependencies = [
|
|||||||
"cxx-gen",
|
"cxx-gen",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"pb-rs",
|
||||||
|
"quick-protobuf",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -345,6 +345,27 @@ impl Directory {
|
|||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn for_all_file<F: FnMut(&DirEntry) -> io::Result<WalkResult>>(
|
||||||
|
&mut self,
|
||||||
|
mut f: F,
|
||||||
|
) -> io::Result<WalkResult> {
|
||||||
|
use WalkResult::*;
|
||||||
|
loop {
|
||||||
|
match self.read()? {
|
||||||
|
None => return Ok(Continue),
|
||||||
|
Some(ref e) => {
|
||||||
|
if e.is_dir() {
|
||||||
|
return Ok(Continue);
|
||||||
|
}
|
||||||
|
match f(e)? {
|
||||||
|
Abort | Skip => return Ok(Continue),
|
||||||
|
Continue => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Directory {
|
impl Directory {
|
||||||
|
@ -83,14 +83,14 @@ macro_rules! bfmt_cstr {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! cstr {
|
macro_rules! cstr {
|
||||||
($str:literal) => {{
|
($($str:tt)*) => {{
|
||||||
assert!(
|
assert!(
|
||||||
!$str.bytes().any(|b| b == b'\0'),
|
!($($str)*).bytes().any(|b| b == b'\0'),
|
||||||
"cstr argument contains embedded NUL bytes",
|
"cstr argument contains embedded NUL bytes",
|
||||||
);
|
);
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::Utf8CStr::from_bytes_unchecked(concat!($str, "\0").as_bytes())
|
$crate::Utf8CStr::from_bytes_unchecked(concat!($($str)*, "\0").as_bytes())
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ fn do_extract_boot_from_payload(
|
|||||||
if !ffi::decompress(data, out_file.as_raw_fd()) {
|
if !ffi::decompress(data, out_file.as_raw_fd()) {
|
||||||
return Err(bad_payload!("decompression failed"));
|
return Err(bad_payload!("decompression failed"));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => return Err(bad_payload!("unsupported operation type")),
|
_ => return Err(bad_payload!("unsupported operation type")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,11 @@ path = "lib.rs"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cxx-gen = { workspace = true }
|
cxx-gen = { workspace = true }
|
||||||
|
pb-rs = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base = { path = "../base" }
|
base = { path = "../base" }
|
||||||
cxx = { workspace = true }
|
cxx = { workspace = true }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
num-derive = { workspace = true }
|
num-derive = { workspace = true }
|
||||||
|
quick-protobuf = { workspace = true }
|
||||||
|
@ -1,8 +1,27 @@
|
|||||||
|
use pb_rs::{types::FileDescriptor, ConfigBuilder};
|
||||||
|
|
||||||
use crate::gen::gen_cxx_binding;
|
use crate::gen::gen_cxx_binding;
|
||||||
|
|
||||||
#[path = "../include/gen.rs"]
|
#[path = "../include/gen.rs"]
|
||||||
mod gen;
|
mod gen;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=resetprop/proto/persistent_properties.proto");
|
||||||
|
|
||||||
gen_cxx_binding("core-rs");
|
gen_cxx_binding("core-rs");
|
||||||
|
|
||||||
|
let cb = ConfigBuilder::new(
|
||||||
|
&["resetprop/proto/persistent_properties.proto"],
|
||||||
|
None,
|
||||||
|
Some(&"resetprop/proto"),
|
||||||
|
&["."],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
FileDescriptor::run(
|
||||||
|
&cb.single_module(true)
|
||||||
|
.dont_use_cow(true)
|
||||||
|
.generate_getters(true)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -5,18 +5,26 @@ use base::Utf8CStr;
|
|||||||
use cert::read_certificate;
|
use cert::read_certificate;
|
||||||
use daemon::{daemon_entry, find_apk_path, get_magiskd, zygisk_entry, MagiskD};
|
use daemon::{daemon_entry, find_apk_path, get_magiskd, zygisk_entry, MagiskD};
|
||||||
use logging::{android_logging, magisk_logging, zygisk_logging};
|
use logging::{android_logging, magisk_logging, zygisk_logging};
|
||||||
|
use resetprop::persist::{
|
||||||
|
persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop,
|
||||||
|
};
|
||||||
|
|
||||||
mod cert;
|
mod cert;
|
||||||
#[path = "../include/consts.rs"]
|
#[path = "../include/consts.rs"]
|
||||||
mod consts;
|
mod consts;
|
||||||
mod daemon;
|
mod daemon;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
mod resetprop;
|
||||||
|
|
||||||
#[cxx::bridge]
|
#[cxx::bridge]
|
||||||
pub mod ffi {
|
pub mod ffi {
|
||||||
extern "C++" {
|
extern "C++" {
|
||||||
|
pub type prop_cb;
|
||||||
include!("resetprop/resetprop.hpp");
|
include!("resetprop/resetprop.hpp");
|
||||||
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
include!("../base/files.hpp");
|
||||||
|
pub unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
||||||
|
pub unsafe fn prop_cb_exec(cb: *mut prop_cb, name: *const c_char, value: *const c_char);
|
||||||
|
pub unsafe fn clone_attr(src: *const c_char, dst: *const c_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
@ -26,6 +34,10 @@ pub mod ffi {
|
|||||||
fn zygisk_logging();
|
fn zygisk_logging();
|
||||||
fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize;
|
fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize;
|
||||||
fn read_certificate(fd: i32, version: i32) -> Vec<u8>;
|
fn read_certificate(fd: i32, version: i32) -> Vec<u8>;
|
||||||
|
unsafe fn persist_get_prop(name: *const c_char, prop_cb: *mut prop_cb);
|
||||||
|
unsafe fn persist_get_props(prop_cb: *mut prop_cb);
|
||||||
|
unsafe fn persist_delete_prop(name: *const c_char) -> bool;
|
||||||
|
unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[namespace = "rust"]
|
#[namespace = "rust"]
|
||||||
|
2
native/src/core/resetprop/.gitignore
vendored
Normal file
2
native/src/core/resetprop/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
proto/mod.rs
|
||||||
|
proto/persistent_properties.rs
|
2
native/src/core/resetprop/mod.rs
Normal file
2
native/src/core/resetprop/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod persist;
|
||||||
|
pub mod proto;
|
@ -1,277 +0,0 @@
|
|||||||
#include <pb.h>
|
|
||||||
#include <pb_decode.h>
|
|
||||||
#include <pb_encode.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
|
|
||||||
#include "resetprop.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/* ***********************************************************************
|
|
||||||
* Auto generated header and field definitions compiled from
|
|
||||||
* https://android.googlesource.com/platform/system/core/+/master/init/persistent_properties.proto
|
|
||||||
* Generated with Nanopb: https://github.com/nanopb/nanopb
|
|
||||||
* ***********************************************************************/
|
|
||||||
|
|
||||||
/* Automatically generated nanopb header */
|
|
||||||
/* Generated by nanopb-0.4.3 */
|
|
||||||
|
|
||||||
#if PB_PROTO_HEADER_VERSION != 40
|
|
||||||
#error Regenerate this file with the current version of nanopb generator.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Struct definitions */
|
|
||||||
struct PersistentProperties {
|
|
||||||
pb_callback_t properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PersistentProperties_PersistentPropertyRecord {
|
|
||||||
pb_callback_t name;
|
|
||||||
bool has_value;
|
|
||||||
char value[92];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Initializer values for message structs */
|
|
||||||
#define PersistentProperties_init_default {{{NULL}, NULL}}
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_init_default {{{NULL}, NULL}, false, ""}
|
|
||||||
#define PersistentProperties_init_zero {{{NULL}, NULL}}
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_init_zero {{{NULL}, NULL}, false, ""}
|
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
|
||||||
#define PersistentProperties_properties_tag 1
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_name_tag 1
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_value_tag 2
|
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
|
||||||
#define PersistentProperties_FIELDLIST(X, a) \
|
|
||||||
X(a, CALLBACK, REPEATED, MESSAGE, properties, 1)
|
|
||||||
#define PersistentProperties_CALLBACK pb_default_field_callback
|
|
||||||
#define PersistentProperties_DEFAULT NULL
|
|
||||||
#define PersistentProperties_properties_MSGTYPE PersistentProperties_PersistentPropertyRecord
|
|
||||||
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_FIELDLIST(X, a) \
|
|
||||||
X(a, CALLBACK, OPTIONAL, STRING, name, 1) \
|
|
||||||
X(a, STATIC, OPTIONAL, STRING, value, 2)
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_CALLBACK pb_default_field_callback
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_DEFAULT NULL
|
|
||||||
|
|
||||||
extern const pb_msgdesc_t PersistentProperties_msg;
|
|
||||||
extern const pb_msgdesc_t PersistentProperties_PersistentPropertyRecord_msg;
|
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
|
||||||
#define PersistentProperties_fields &PersistentProperties_msg
|
|
||||||
#define PersistentProperties_PersistentPropertyRecord_fields &PersistentProperties_PersistentPropertyRecord_msg
|
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
|
||||||
/* PersistentProperties_size depends on runtime parameters */
|
|
||||||
/* PersistentProperties_PersistentPropertyRecord_size depends on runtime parameters */
|
|
||||||
|
|
||||||
PB_BIND(PersistentProperties, PersistentProperties, AUTO)
|
|
||||||
|
|
||||||
PB_BIND(PersistentProperties_PersistentPropertyRecord, PersistentProperties_PersistentPropertyRecord, AUTO)
|
|
||||||
|
|
||||||
/* ***************************
|
|
||||||
* End of auto generated code
|
|
||||||
* ***************************/
|
|
||||||
|
|
||||||
#define PERSIST_PROP_DIR "/data/property"
|
|
||||||
#define PERSIST_PROP PERSIST_PROP_DIR "/persistent_properties"
|
|
||||||
|
|
||||||
static bool name_decode(pb_istream_t *stream, const pb_field_t *, void **arg) {
|
|
||||||
string &name = *static_cast<string *>(*arg);
|
|
||||||
name.resize(stream->bytes_left);
|
|
||||||
return pb_read(stream, (pb_byte_t *)(name.data()), stream->bytes_left);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool name_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
|
|
||||||
return pb_encode_tag_for_field(stream, field) &&
|
|
||||||
pb_encode_string(stream, (const pb_byte_t *) *arg, strlen((const char *) *arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool prop_decode(pb_istream_t *stream, const pb_field_t *, void **arg) {
|
|
||||||
PersistentProperties_PersistentPropertyRecord prop{};
|
|
||||||
string name;
|
|
||||||
prop.name.funcs.decode = name_decode;
|
|
||||||
prop.name.arg = &name;
|
|
||||||
if (!pb_decode(stream, &PersistentProperties_PersistentPropertyRecord_msg, &prop))
|
|
||||||
return false;
|
|
||||||
auto cb = static_cast<prop_cb*>(*arg);
|
|
||||||
cb->exec(name.data(), prop.value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool prop_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
|
|
||||||
PersistentProperties_PersistentPropertyRecord prop{};
|
|
||||||
prop.name.funcs.encode = name_encode;
|
|
||||||
prop.has_value = true;
|
|
||||||
prop_list &list = *static_cast<prop_list *>(*arg);
|
|
||||||
for (auto &p : list) {
|
|
||||||
if (!pb_encode_tag_for_field(stream, field))
|
|
||||||
return false;
|
|
||||||
prop.name.arg = (void *) p.first.data();
|
|
||||||
strscpy(prop.value, p.second.data(), sizeof(prop.value));
|
|
||||||
if (!pb_encode_submessage(stream, &PersistentProperties_PersistentPropertyRecord_msg, &prop))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) {
|
|
||||||
int fd = (intptr_t)stream->state;
|
|
||||||
return xwrite(fd, buf, count) == count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pb_ostream_t create_ostream(int fd) {
|
|
||||||
pb_ostream_t o = {
|
|
||||||
.callback = write_callback,
|
|
||||||
.state = (void*)(intptr_t)fd,
|
|
||||||
.max_size = SIZE_MAX,
|
|
||||||
.bytes_written = 0,
|
|
||||||
};
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pb_get_prop(prop_cb *prop_cb) {
|
|
||||||
LOGD("resetprop: decode with protobuf [" PERSIST_PROP "]\n");
|
|
||||||
PersistentProperties props{};
|
|
||||||
props.properties.funcs.decode = prop_decode;
|
|
||||||
props.properties.arg = prop_cb;
|
|
||||||
mmap_data m(PERSIST_PROP);
|
|
||||||
pb_istream_t stream = pb_istream_from_buffer(m.buf(), m.sz());
|
|
||||||
pb_decode(&stream, &PersistentProperties_msg, &props);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool pb_write_props(prop_list &list) {
|
|
||||||
char tmp[4096];
|
|
||||||
strscpy(tmp, PERSIST_PROP ".XXXXXX", sizeof(tmp));
|
|
||||||
int fd = mkostemp(tmp, O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pb_ostream_t ostream = create_ostream(fd);
|
|
||||||
PersistentProperties props{};
|
|
||||||
props.properties.funcs.encode = prop_encode;
|
|
||||||
props.properties.arg = &list;
|
|
||||||
LOGD("resetprop: encode with protobuf [%s]\n", tmp);
|
|
||||||
bool ret = pb_encode(&ostream, &PersistentProperties_msg, &props);
|
|
||||||
close(fd);
|
|
||||||
if (!ret)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
clone_attr(PERSIST_PROP, tmp);
|
|
||||||
return rename(tmp, PERSIST_PROP) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool file_get_prop(const char *name, char *value) {
|
|
||||||
char path[4096];
|
|
||||||
ssprintf(path, sizeof(path), PERSIST_PROP_DIR "/%s", name);
|
|
||||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return false;
|
|
||||||
LOGD("resetprop: read prop from [%s]\n", path);
|
|
||||||
value[read(fd, value, PROP_VALUE_MAX - 1)] = '\0'; // Null terminate the read value
|
|
||||||
close(fd);
|
|
||||||
return value[0] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool file_set_prop(const char *name, const char *value) {
|
|
||||||
char tmp[4096];
|
|
||||||
strscpy(tmp, PERSIST_PROP_DIR "/prop.XXXXXX", sizeof(tmp));
|
|
||||||
int fd = mkostemp(tmp, O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return false;
|
|
||||||
auto len = strlen(value);
|
|
||||||
LOGD("resetprop: write prop to [%s]\n", tmp);
|
|
||||||
bool ret = write(fd, value, len) == len;
|
|
||||||
close(fd);
|
|
||||||
if (!ret)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
char path[4096];
|
|
||||||
ssprintf(path, sizeof(path), PERSIST_PROP_DIR "/%s", name);
|
|
||||||
return rename(tmp, path) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_pb() {
|
|
||||||
static bool use_pb = access(PERSIST_PROP, R_OK) == 0;
|
|
||||||
return use_pb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void persist_get_props(prop_cb *prop_cb) {
|
|
||||||
if (check_pb()) {
|
|
||||||
pb_get_prop(prop_cb);
|
|
||||||
} else {
|
|
||||||
auto dir = open_dir(PERSIST_PROP_DIR);
|
|
||||||
if (!dir) return;
|
|
||||||
char value[PROP_VALUE_MAX];
|
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
|
||||||
if (file_get_prop(entry->d_name, value))
|
|
||||||
prop_cb->exec(entry->d_name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct match_prop_name : prop_cb {
|
|
||||||
explicit match_prop_name(const char *name) : _name(name) { value[0] = '\0'; }
|
|
||||||
void exec(const char *name, const char *val) override {
|
|
||||||
if (value[0] == '\0' && _name == name)
|
|
||||||
strscpy(value, val, sizeof(value));
|
|
||||||
}
|
|
||||||
char value[PROP_VALUE_MAX];
|
|
||||||
private:
|
|
||||||
string_view _name;
|
|
||||||
};
|
|
||||||
|
|
||||||
void persist_get_prop(const char *name, prop_cb *prop_cb) {
|
|
||||||
if (check_pb()) {
|
|
||||||
match_prop_name cb(name);
|
|
||||||
pb_get_prop(&cb);
|
|
||||||
if (cb.value[0]) {
|
|
||||||
LOGD("resetprop: get prop (persist) [%s]: [%s]\n", name, cb.value);
|
|
||||||
prop_cb->exec(name, cb.value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Try to read from file
|
|
||||||
char value[PROP_VALUE_MAX];
|
|
||||||
if (file_get_prop(name, value)) {
|
|
||||||
LOGD("resetprop: get prop (persist) [%s]: [%s]\n", name, value);
|
|
||||||
prop_cb->exec(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool persist_delete_prop(const char *name) {
|
|
||||||
if (check_pb()) {
|
|
||||||
prop_list list;
|
|
||||||
prop_collector collector(list);
|
|
||||||
pb_get_prop(&collector);
|
|
||||||
|
|
||||||
auto it = list.find(name);
|
|
||||||
if (it != list.end()) {
|
|
||||||
list.erase(it);
|
|
||||||
return pb_write_props(list);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
char path[4096];
|
|
||||||
ssprintf(path, sizeof(path), PERSIST_PROP_DIR "/%s", name);
|
|
||||||
if (unlink(path) == 0) {
|
|
||||||
LOGD("resetprop: unlink [%s]\n", path);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool persist_set_prop(const char *name, const char *value) {
|
|
||||||
if (check_pb()) {
|
|
||||||
prop_list list;
|
|
||||||
prop_collector collector(list);
|
|
||||||
pb_get_prop(&collector);
|
|
||||||
list[name] = value;
|
|
||||||
return pb_write_props(list);
|
|
||||||
} else {
|
|
||||||
return file_set_prop(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
232
native/src/core/resetprop/persist.rs
Normal file
232
native/src/core/resetprop/persist.rs
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
use crate::ffi::{clone_attr, prop_cb, prop_cb_exec};
|
||||||
|
use crate::resetprop::proto::persistent_properties::{
|
||||||
|
mod_PersistentProperties::PersistentPropertyRecord, PersistentProperties,
|
||||||
|
};
|
||||||
|
use base::{cstr, debug, libc::mkstemp, Directory, LoggedResult, MappedFile, Utf8CStr, WalkResult};
|
||||||
|
use core::ffi::c_char;
|
||||||
|
use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
|
||||||
|
use std::{
|
||||||
|
fs::{read_to_string, remove_file, rename, File},
|
||||||
|
io::{BufWriter, Write},
|
||||||
|
os::fd::FromRawFd,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! PERSIST_PROP_DIR {
|
||||||
|
() => {
|
||||||
|
"/data/property"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! PERSIST_PROP {
|
||||||
|
() => {
|
||||||
|
concat!(PERSIST_PROP_DIR!(), "/persistent_properties")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PropCb {
|
||||||
|
cb: *mut prop_cb,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MatchNameCb<'a> {
|
||||||
|
cb: PropCb,
|
||||||
|
name: &'a Utf8CStr,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PropCollectCb<'a> {
|
||||||
|
props: &'a mut PersistentProperties,
|
||||||
|
replace_name: Option<&'a Utf8CStr>,
|
||||||
|
replace_value: Option<&'a Utf8CStr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PropCbExec {
|
||||||
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropCbExec for PropCb {
|
||||||
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
||||||
|
if !self.cb.is_null() {
|
||||||
|
unsafe { prop_cb_exec(self.cb, name.as_ptr(), value.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropCbExec for MatchNameCb<'_> {
|
||||||
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
||||||
|
if name.as_bytes() == self.name.as_bytes() {
|
||||||
|
self.cb.exec(name, value);
|
||||||
|
debug!("resetprop: found prop [{}] = [{}]", name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropCbExec for PropCollectCb<'_> {
|
||||||
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
||||||
|
let replace_value = self.replace_value.unwrap_or(value);
|
||||||
|
let value = self.replace_name.map_or(value, |replace_name| {
|
||||||
|
if name.as_bytes() == replace_name.as_bytes() {
|
||||||
|
replace_value
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.props.properties.push(PersistentPropertyRecord {
|
||||||
|
name: Some(name.to_string()),
|
||||||
|
value: Some(value.to_string()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_pb() -> bool {
|
||||||
|
Path::new(PERSIST_PROP!()).exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pb_get_prop(cb: &mut dyn PropCbExec) -> LoggedResult<()> {
|
||||||
|
debug!("resetprop: decode with protobuf [{}]", PERSIST_PROP!());
|
||||||
|
let m = MappedFile::open(cstr!(PERSIST_PROP!()))?;
|
||||||
|
let m = m.as_ref();
|
||||||
|
let mut r = BytesReader::from_bytes(m);
|
||||||
|
let mut pp = PersistentProperties::from_reader(&mut r, m)?;
|
||||||
|
pp.properties.iter_mut().for_each(|p| {
|
||||||
|
if let PersistentPropertyRecord {
|
||||||
|
name: Some(ref mut n),
|
||||||
|
value: Some(ref mut v),
|
||||||
|
} = p
|
||||||
|
{
|
||||||
|
cb.exec(Utf8CStr::from_string(n), Utf8CStr::from_string(v));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_get_prop(name: &Utf8CStr) -> LoggedResult<String> {
|
||||||
|
let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
|
||||||
|
let path = path.as_path();
|
||||||
|
debug!("resetprop: read prop from [{}]\n", path.display());
|
||||||
|
Ok(read_to_string(path)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pb_write_props(props: &PersistentProperties) -> LoggedResult<()> {
|
||||||
|
let mut tmp = String::from(concat!(PERSIST_PROP!(), ".XXXXXX"));
|
||||||
|
let tmp = Utf8CStr::from_string(&mut tmp);
|
||||||
|
{
|
||||||
|
let f = unsafe {
|
||||||
|
let fd = mkstemp(tmp.as_ptr() as *mut c_char);
|
||||||
|
if fd < 0 {
|
||||||
|
return Err(Default::default());
|
||||||
|
}
|
||||||
|
File::from_raw_fd(fd)
|
||||||
|
};
|
||||||
|
debug!("resetprop: encode with protobuf [{}]", tmp);
|
||||||
|
props.write_message(&mut Writer::new(BufWriter::new(f)))?;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
clone_attr(cstr!(PERSIST_PROP!()).as_ptr(), tmp.as_ptr());
|
||||||
|
}
|
||||||
|
rename(tmp, PERSIST_PROP!())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_set_prop(name: &Utf8CStr, value: Option<&Utf8CStr>) -> LoggedResult<()> {
|
||||||
|
let path = PathBuf::new().join(PERSIST_PROP_DIR!()).join(name);
|
||||||
|
let path = path.as_path();
|
||||||
|
if let Some(value) = value {
|
||||||
|
let mut tmp = String::from(concat!(PERSIST_PROP_DIR!(), ".prop.XXXXXX"));
|
||||||
|
{
|
||||||
|
let mut f = unsafe {
|
||||||
|
let fd = mkstemp(tmp.as_mut_ptr() as *mut c_char);
|
||||||
|
if fd < 0 {
|
||||||
|
return Err(Default::default());
|
||||||
|
}
|
||||||
|
File::from_raw_fd(fd)
|
||||||
|
};
|
||||||
|
f.write_all(value.as_bytes())?;
|
||||||
|
}
|
||||||
|
debug!("resetprop: write prop to [{}]\n", tmp);
|
||||||
|
rename(tmp, path)?;
|
||||||
|
} else {
|
||||||
|
debug!("resetprop: unlink [{}]\n", path.display());
|
||||||
|
remove_file(path)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_persist_get_prop(name: &Utf8CStr, mut prop_cb: PropCb) -> LoggedResult<()> {
|
||||||
|
if check_pb() {
|
||||||
|
pb_get_prop(&mut MatchNameCb { cb: prop_cb, name })
|
||||||
|
} else {
|
||||||
|
let mut value = file_get_prop(name)?;
|
||||||
|
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
||||||
|
debug!("resetprop: found prop [{}] = [{}]", name, value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_persist_get_props(mut prop_cb: PropCb) -> LoggedResult<()> {
|
||||||
|
if check_pb() {
|
||||||
|
pb_get_prop(&mut prop_cb)
|
||||||
|
} else {
|
||||||
|
let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR!()))?;
|
||||||
|
dir.for_all_file(|f| {
|
||||||
|
if let Ok(name) = Utf8CStr::from_bytes(f.d_name().to_bytes()) {
|
||||||
|
if let Ok(mut value) = file_get_prop(name) {
|
||||||
|
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(WalkResult::Continue)
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_persist_delete_prop(name: &Utf8CStr) -> LoggedResult<()> {
|
||||||
|
if check_pb() {
|
||||||
|
let mut pp = PersistentProperties { properties: vec![] };
|
||||||
|
pb_get_prop(&mut PropCollectCb {
|
||||||
|
props: &mut pp,
|
||||||
|
replace_name: Some(name),
|
||||||
|
replace_value: None,
|
||||||
|
})?;
|
||||||
|
pb_write_props(&pp)
|
||||||
|
} else {
|
||||||
|
file_set_prop(name, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_persist_set_prop(name: &Utf8CStr, value: &Utf8CStr) -> LoggedResult<()> {
|
||||||
|
if check_pb() {
|
||||||
|
let mut pp = PersistentProperties { properties: vec![] };
|
||||||
|
pb_get_prop(&mut PropCollectCb {
|
||||||
|
props: &mut pp,
|
||||||
|
replace_name: Some(name),
|
||||||
|
replace_value: Some(value),
|
||||||
|
})?;
|
||||||
|
pb_write_props(&pp)
|
||||||
|
} else {
|
||||||
|
file_set_prop(name, Some(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn persist_get_prop(name: *const c_char, prop_cb: *mut prop_cb) {
|
||||||
|
unsafe fn inner(name: *const c_char, prop_cb: *mut prop_cb) -> LoggedResult<()> {
|
||||||
|
do_persist_get_prop(Utf8CStr::from_ptr(name)?, PropCb { cb: prop_cb })
|
||||||
|
}
|
||||||
|
inner(name, prop_cb).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn persist_get_props(prop_cb: *mut prop_cb) {
|
||||||
|
do_persist_get_props(PropCb { cb: prop_cb }).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn persist_delete_prop(name: *const c_char) -> bool {
|
||||||
|
unsafe fn inner(name: *const c_char) -> LoggedResult<()> {
|
||||||
|
do_persist_delete_prop(Utf8CStr::from_ptr(name)?)
|
||||||
|
}
|
||||||
|
inner(name).is_ok()
|
||||||
|
}
|
||||||
|
pub unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool {
|
||||||
|
unsafe fn inner(name: *const c_char, value: *const c_char) -> LoggedResult<()> {
|
||||||
|
do_persist_set_prop(Utf8CStr::from_ptr(name)?, Utf8CStr::from_ptr(value)?)
|
||||||
|
}
|
||||||
|
inner(name, value).is_ok()
|
||||||
|
}
|
24
native/src/core/resetprop/proto/persistent_properties.proto
Normal file
24
native/src/core/resetprop/proto/persistent_properties.proto
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
syntax = "proto2";
|
||||||
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
message PersistentProperties {
|
||||||
|
message PersistentPropertyRecord {
|
||||||
|
optional string name = 1;
|
||||||
|
optional string value = 2;
|
||||||
|
}
|
||||||
|
repeated PersistentPropertyRecord properties = 1;
|
||||||
|
}
|
@ -29,7 +29,11 @@ int delete_prop(const char *name, bool persist = false);
|
|||||||
int set_prop(const char *name, const char *value, bool skip_svc = false);
|
int set_prop(const char *name, const char *value, bool skip_svc = false);
|
||||||
void load_prop_file(const char *filename, bool skip_svc = false);
|
void load_prop_file(const char *filename, bool skip_svc = false);
|
||||||
|
|
||||||
void persist_get_prop(const char *name, prop_cb *prop_cb);
|
inline void prop_cb_exec(prop_cb *cb, const char *name, const char *value) {
|
||||||
void persist_get_props(prop_cb *prop_cb);
|
cb->exec(name, value);
|
||||||
bool persist_delete_prop(const char *name);
|
}
|
||||||
bool persist_set_prop(const char *name, const char *value);
|
|
||||||
|
void persist_get_prop(const char *name, prop_cb *prop_cb) noexcept;
|
||||||
|
void persist_get_props(prop_cb *prop_cb) noexcept;
|
||||||
|
bool persist_delete_prop(const char *name) noexcept;
|
||||||
|
bool persist_set_prop(const char *name, const char *value) noexcept;
|
||||||
|
11
native/src/external/Android.mk
vendored
11
native/src/external/Android.mk
vendored
@ -17,17 +17,6 @@ LOCAL_SRC_FILES := \
|
|||||||
xz-embedded/xz_dec_stream.c
|
xz-embedded/xz_dec_stream.c
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
# libnanopb.a
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
LOCAL_MODULE:= libnanopb
|
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/nanopb
|
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
|
||||||
LOCAL_SRC_FILES := \
|
|
||||||
nanopb/pb_common.c \
|
|
||||||
nanopb/pb_decode.c \
|
|
||||||
nanopb/pb_encode.c
|
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
|
||||||
|
|
||||||
# libfdt.a
|
# libfdt.a
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE:= libfdt
|
LOCAL_MODULE:= libfdt
|
||||||
|
1
native/src/external/nanopb
vendored
1
native/src/external/nanopb
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit c9124132a604047d0ef97a09c0e99cd9bed2c818
|
|
Loading…
x
Reference in New Issue
Block a user