mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-03 10:47:38 +00:00
Add resetprop -w
for waiting property change
It's very easy to wait for property change both in Java and C++, but it's not the case in shell script. With this patch, developers can now easily to wait for property change, just like what we have in `.rc` files, and to wait for boot complete.
This commit is contained in:
parent
27ece3c7df
commit
e94d65b4b2
@ -109,7 +109,7 @@ Update JSON format:
|
|||||||
|
|
||||||
#### Shell scripts (`*.sh`)
|
#### Shell scripts (`*.sh`)
|
||||||
|
|
||||||
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script.
|
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script. If you need to wait for boot completed, you can use `resetprop -w sys.boot_completed 0`.
|
||||||
|
|
||||||
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
|
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
|
||||||
If Zygisk is enabled, the environment variable `ZYGISK_ENABLED` will be set to `1`.
|
If Zygisk is enabled, the environment variable `ZYGISK_ENABLED` will be set to `1`.
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
#include <cxx.h>
|
#include <cxx.h>
|
||||||
|
|
||||||
struct prop_cb {
|
struct prop_cb {
|
||||||
virtual void exec(const char *name, const char *value) = 0;
|
virtual void exec(const char *name, const char *value, uint32_t serial) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using prop_list = std::map<std::string, std::string>;
|
using prop_list = std::map<std::string, std::string>;
|
||||||
|
|
||||||
struct prop_collector : prop_cb {
|
struct prop_collector : prop_cb {
|
||||||
explicit prop_collector(prop_list &list) : list(list) {}
|
explicit prop_collector(prop_list &list) : list(list) {}
|
||||||
void exec(const char *name, const char *value) override {
|
void exec(const char *name, const char *value, uint32_t) override {
|
||||||
list.insert({name, value});
|
list.insert({name, value});
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@ -26,6 +26,6 @@ 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);
|
||||||
|
|
||||||
static inline void prop_cb_exec(prop_cb &cb, const char *name, const char *value) {
|
static inline void prop_cb_exec(prop_cb &cb, const char *name, const char *value, uint32_t serial) {
|
||||||
cb.exec(name, value);
|
cb.exec(name, value, serial);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,12 @@ pub mod ffi {
|
|||||||
#[cxx_name = "prop_cb"]
|
#[cxx_name = "prop_cb"]
|
||||||
type PropCb;
|
type PropCb;
|
||||||
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
|
||||||
unsafe fn prop_cb_exec(cb: Pin<&mut PropCb>, name: *const c_char, value: *const c_char);
|
unsafe fn prop_cb_exec(
|
||||||
|
cb: Pin<&mut PropCb>,
|
||||||
|
name: *const c_char,
|
||||||
|
value: *const c_char,
|
||||||
|
serial: u32,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
|
@ -39,7 +39,7 @@ trait PropCbExec {
|
|||||||
|
|
||||||
impl PropCbExec for Pin<&mut PropCb> {
|
impl PropCbExec for Pin<&mut PropCb> {
|
||||||
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
|
||||||
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr()) }
|
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr(), u32::MAX) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,10 +33,12 @@ struct PropFlags {
|
|||||||
void setPersist() { flags |= (1 << 1); }
|
void setPersist() { flags |= (1 << 1); }
|
||||||
void setContext() { flags |= (1 << 2); }
|
void setContext() { flags |= (1 << 2); }
|
||||||
void setPersistOnly() { flags |= (1 << 3); setPersist(); }
|
void setPersistOnly() { flags |= (1 << 3); setPersist(); }
|
||||||
|
void setWait() { flags |= (1 << 4); }
|
||||||
bool isSkipSvc() const { return flags & 1; }
|
bool isSkipSvc() const { return flags & 1; }
|
||||||
bool isPersist() const { return flags & (1 << 1); }
|
bool isPersist() const { return flags & (1 << 1); }
|
||||||
bool isContext() const { return flags & (1 << 2); }
|
bool isContext() const { return flags & (1 << 2); }
|
||||||
bool isPersistOnly() const { return flags & (1 << 3); }
|
bool isPersistOnly() const { return flags & (1 << 3); }
|
||||||
|
bool isWait() const { return flags & (1 << 4); }
|
||||||
private:
|
private:
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
};
|
};
|
||||||
@ -49,7 +51,7 @@ Usage: %s [flags] [arguments...]
|
|||||||
|
|
||||||
Read mode arguments:
|
Read mode arguments:
|
||||||
(no arguments) print all properties
|
(no arguments) print all properties
|
||||||
NAME get property
|
NAME [OLD_VALUE] get property of NAME, optionally with an OLD_VALUE for -w
|
||||||
|
|
||||||
Write mode arguments:
|
Write mode arguments:
|
||||||
NAME VALUE set property NAME as VALUE
|
NAME VALUE set property NAME as VALUE
|
||||||
@ -64,6 +66,8 @@ Read mode flags:
|
|||||||
-p also read persistent props from storage
|
-p also read persistent props from storage
|
||||||
-P only read persistent props from storage
|
-P only read persistent props from storage
|
||||||
-Z get property context instead of value
|
-Z get property context instead of value
|
||||||
|
-w wait for property change, and if OLD_VALUE is specified, wait for it to change to other value
|
||||||
|
return immediately if persistent
|
||||||
|
|
||||||
Write mode flags:
|
Write mode flags:
|
||||||
-n set properties bypassing property_service
|
-n set properties bypassing property_service
|
||||||
@ -104,8 +108,8 @@ illegal:
|
|||||||
|
|
||||||
static void read_prop_with_cb(const prop_info *pi, void *cb) {
|
static void read_prop_with_cb(const prop_info *pi, void *cb) {
|
||||||
if (system_property_read_callback) {
|
if (system_property_read_callback) {
|
||||||
auto callback = [](void *cb, const char *name, const char *value, uint32_t) {
|
auto callback = [](void *cb, const char *name, const char *value, uint32_t serial) {
|
||||||
static_cast<prop_cb*>(cb)->exec(name, value);
|
static_cast<prop_cb*>(cb)->exec(name, value, serial);
|
||||||
};
|
};
|
||||||
system_property_read_callback(pi, callback, cb);
|
system_property_read_callback(pi, callback, cb);
|
||||||
} else {
|
} else {
|
||||||
@ -114,19 +118,21 @@ static void read_prop_with_cb(const prop_info *pi, void *cb) {
|
|||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
value[0] = '\0';
|
value[0] = '\0';
|
||||||
system_property_read(pi, name, value);
|
system_property_read(pi, name, value);
|
||||||
static_cast<prop_cb*>(cb)->exec(name, value);
|
static_cast<prop_cb*>(cb)->exec(name, value, pi->serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class StringType>
|
template<class StringType>
|
||||||
struct prop_to_string : prop_cb {
|
struct prop_to_string : prop_cb {
|
||||||
void exec(const char *, const char *value) override {
|
void exec(const char *, const char *value, uint32_t serial) override {
|
||||||
val = value;
|
val = value;
|
||||||
|
s = serial;
|
||||||
}
|
}
|
||||||
StringType val;
|
StringType val;
|
||||||
|
uint32_t s;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> void prop_to_string<rust::String>::exec(const char *, const char *value) {
|
template<> void prop_to_string<rust::String>::exec(const char *, const char *value, uint32_t) {
|
||||||
// We do not want to crash when values are not UTF-8
|
// We do not want to crash when values are not UTF-8
|
||||||
val = rust::String::lossy(value);
|
val = rust::String::lossy(value);
|
||||||
}
|
}
|
||||||
@ -181,7 +187,7 @@ static int set_prop(const char *name, const char *value, PropFlags flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class StringType>
|
template<class StringType>
|
||||||
static StringType get_prop(const char *name, PropFlags flags) {
|
static StringType get_prop(const char *name, PropFlags flags, const char *wait_value = nullptr) {
|
||||||
if (!check_legal_property_name(name))
|
if (!check_legal_property_name(name))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -190,15 +196,20 @@ static StringType get_prop(const char *name, PropFlags flags) {
|
|||||||
if (flags.isContext()) {
|
if (flags.isContext()) {
|
||||||
auto context = __system_property_get_context(name) ?: "";
|
auto context = __system_property_get_context(name) ?: "";
|
||||||
LOGD("resetprop: prop context [%s]: [%s]\n", name, context);
|
LOGD("resetprop: prop context [%s]: [%s]\n", name, context);
|
||||||
cb.exec(name, context);
|
cb.exec(name, context, -1);
|
||||||
return cb.val;
|
return cb.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags.isPersistOnly()) {
|
if (!flags.isPersistOnly()) {
|
||||||
if (auto pi = system_property_find(name)) {
|
auto pi = system_property_find(name);
|
||||||
|
if (!pi) return {};
|
||||||
|
read_prop_with_cb(pi, &cb);
|
||||||
|
if (flags.isWait() && (wait_value == nullptr || cb.val == wait_value)) {
|
||||||
|
uint32_t new_serial;
|
||||||
|
__system_property_wait(pi, cb.s, &new_serial, nullptr);
|
||||||
read_prop_with_cb(pi, &cb);
|
read_prop_with_cb(pi, &cb);
|
||||||
LOGD("resetprop: get prop [%s]: [%s]\n", name, cb.val.c_str());
|
|
||||||
}
|
}
|
||||||
|
LOGD("resetprop: get prop [%s]: [%s]\n", name, cb.val.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb.val.empty() && flags.isPersist() && str_starts(name, "persist."))
|
if (cb.val.empty() && flags.isPersist() && str_starts(name, "persist."))
|
||||||
@ -319,6 +330,9 @@ int resetprop_main(int argc, char *argv[]) {
|
|||||||
case 'Z':
|
case 'Z':
|
||||||
flags.setContext();
|
flags.setContext();
|
||||||
continue;
|
continue;
|
||||||
|
case 'w':
|
||||||
|
flags.setWait();
|
||||||
|
continue;
|
||||||
case '\0':
|
case '\0':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -355,7 +369,15 @@ int resetprop_main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
return set_prop(argv[0], argv[1], flags);
|
if (flags.isWait()) {
|
||||||
|
auto val = get_prop<string>(argv[0], flags, argv[1]);
|
||||||
|
if (val.empty())
|
||||||
|
return 1;
|
||||||
|
printf("%s\n", val.data());
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return set_prop(argv[0], argv[1], flags);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
usage(argv0);
|
usage(argv0);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user