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"]
|
||||
path = native/src/external/xz
|
||||
url = https://github.com/xz-mirror/xz.git
|
||||
[submodule "nanopb"]
|
||||
path = native/src/external/nanopb
|
||||
url = https://github.com/nanopb/nanopb.git
|
||||
[submodule "pcre"]
|
||||
path = native/src/external/pcre
|
||||
url = https://android.googlesource.com/platform/external/pcre
|
||||
|
@ -10,7 +10,6 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magisk
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libnanopb \
|
||||
libsystemproperties \
|
||||
libphmap \
|
||||
liblsplt \
|
||||
@ -28,7 +27,6 @@ LOCAL_SRC_FILES := \
|
||||
core/restorecon.cpp \
|
||||
core/module.cpp \
|
||||
core/thread.cpp \
|
||||
core/resetprop/persist.cpp \
|
||||
core/resetprop/resetprop.cpp \
|
||||
core/core-rs.cpp \
|
||||
core/su/su.cpp \
|
||||
@ -139,14 +137,13 @@ include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := resetprop
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libbase \
|
||||
libnanopb \
|
||||
libsystemproperties \
|
||||
libmagisk-rs
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/applet_stub.cpp \
|
||||
core/resetprop/resetprop.cpp \
|
||||
core/resetprop/persist.cpp
|
||||
core/core-rs.cpp
|
||||
|
||||
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=resetprop_main
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
2
native/src/Cargo.lock
generated
2
native/src/Cargo.lock
generated
@ -424,6 +424,8 @@ dependencies = [
|
||||
"cxx-gen",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pb-rs",
|
||||
"quick-protobuf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -345,6 +345,27 @@ impl Directory {
|
||||
})?;
|
||||
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 {
|
||||
|
@ -83,14 +83,14 @@ macro_rules! bfmt_cstr {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cstr {
|
||||
($str:literal) => {{
|
||||
($($str:tt)*) => {{
|
||||
assert!(
|
||||
!$str.bytes().any(|b| b == b'\0'),
|
||||
!($($str)*).bytes().any(|b| b == b'\0'),
|
||||
"cstr argument contains embedded NUL bytes",
|
||||
);
|
||||
#[allow(unused_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()) {
|
||||
return Err(bad_payload!("decompression failed"));
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => return Err(bad_payload!("unsupported operation type")),
|
||||
};
|
||||
}
|
||||
|
@ -9,9 +9,11 @@ path = "lib.rs"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-gen = { workspace = true }
|
||||
pb-rs = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
base = { path = "../base" }
|
||||
cxx = { workspace = true }
|
||||
num-traits = { 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;
|
||||
|
||||
#[path = "../include/gen.rs"]
|
||||
mod gen;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=resetprop/proto/persistent_properties.proto");
|
||||
|
||||
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 daemon::{daemon_entry, find_apk_path, get_magiskd, zygisk_entry, MagiskD};
|
||||
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;
|
||||
#[path = "../include/consts.rs"]
|
||||
mod consts;
|
||||
mod daemon;
|
||||
mod logging;
|
||||
mod resetprop;
|
||||
|
||||
#[cxx::bridge]
|
||||
pub mod ffi {
|
||||
extern "C++" {
|
||||
pub type prop_cb;
|
||||
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" {
|
||||
@ -26,6 +34,10 @@ pub mod ffi {
|
||||
fn zygisk_logging();
|
||||
fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize;
|
||||
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"]
|
||||
|
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);
|
||||
void load_prop_file(const char *filename, bool skip_svc = false);
|
||||
|
||||
void persist_get_prop(const char *name, prop_cb *prop_cb);
|
||||
void persist_get_props(prop_cb *prop_cb);
|
||||
bool persist_delete_prop(const char *name);
|
||||
bool persist_set_prop(const char *name, const char *value);
|
||||
inline void prop_cb_exec(prop_cb *cb, const char *name, const char *value) {
|
||||
cb->exec(name, 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
|
||||
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
|
||||
include $(CLEAR_VARS)
|
||||
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