diff --git a/native/jni/include/resetprop.hpp b/native/jni/include/resetprop.hpp index 12b272ede..558ba4735 100644 --- a/native/jni/include/resetprop.hpp +++ b/native/jni/include/resetprop.hpp @@ -3,7 +3,6 @@ #include #include -bool prop_exist(const char *name); int setprop(const char *name, const char *value, bool trigger = true); std::string getprop(const char *name, bool persist = false); void getprops(void (*callback)(const char *, const char *, void *), diff --git a/native/jni/resetprop/persist_properties.cpp b/native/jni/resetprop/persist_properties.cpp index b5d0b5b0c..f31657fa4 100644 --- a/native/jni/resetprop/persist_properties.cpp +++ b/native/jni/resetprop/persist_properties.cpp @@ -88,6 +88,8 @@ const pb_field_t PersistentProperties_fields[2] = { * End of auto generated code * ***************************/ +bool use_pb = false; + #ifdef APPLET_STUB_MAIN struct { void push_back(...){}; diff --git a/native/jni/resetprop/resetprop.cpp b/native/jni/resetprop/resetprop.cpp index dcf0ed642..dbf55b5a7 100644 --- a/native/jni/resetprop/resetprop.cpp +++ b/native/jni/resetprop/resetprop.cpp @@ -1,10 +1,4 @@ -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include @@ -21,37 +15,10 @@ using namespace std; -bool use_pb = false; static bool verbose = false; -static bool check_legal_property_name(const char *name) { - int namelen = strlen(name); - - if (namelen < 1) goto illegal; - if (name[0] == '.') goto illegal; - if (name[namelen - 1] == '.') goto illegal; - - /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ - /* Don't allow ".." to appear in a property name */ - for (size_t i = 0; i < namelen; i++) { - if (name[i] == '.') { - // i=0 is guaranteed to never have a dot. See above. - if (name[i-1] == '.') goto illegal; - continue; - } - if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue; - if (name[i] >= 'a' && name[i] <= 'z') continue; - if (name[i] >= 'A' && name[i] <= 'Z') continue; - if (name[i] >= '0' && name[i] <= '9') continue; - goto illegal; - } - - return true; - -illegal: - LOGE("Illegal property name: [%s]\n", name); - return false; -} +static int (*system_property_get)(const char*, char*); +static int (*system_property_set)(const char*, const char*); [[noreturn]] static void usage(char* arg0) { fprintf(stderr, @@ -78,126 +45,200 @@ Flags: exit(1); } -static void read_props(const prop_info *pi, void *cb) { +static bool check_legal_property_name(const char *name) { + int namelen = strlen(name); + + if (namelen < 1) goto illegal; + if (name[0] == '.') goto illegal; + if (name[namelen - 1] == '.') goto illegal; + + /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ + /* Don't allow ".." to appear in a property name */ + for (size_t i = 0; i < namelen; i++) { + if (name[i] == '.') { + // i=0 is guaranteed to never have a dot. See above. + if (name[i-1] == '.') goto illegal; + continue; + } + if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue; + if (name[i] >= 'a' && name[i] <= 'z') continue; + if (name[i] >= 'A' && name[i] <= 'Z') continue; + if (name[i] >= '0' && name[i] <= '9') continue; + goto illegal; + } + + return true; + + illegal: + LOGE("Illegal property name: [%s]\n", name); + return false; +} + +static void read_prop(const prop_info *pi, void *cb) { __system_property_read_callback( pi, [](auto cb, auto name, auto value, auto) { reinterpret_cast(cb)->exec(name, value); }, cb); } -static int init_resetprop() { - use_pb = use_pb ? true : access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0; - if (__system_properties_init()) { - LOGE("resetprop: Initialize error\n"); - return -1; - } - return 0; -} - static void print_props(bool persist) { getprops([](auto name, auto value, auto) { printf("[%s]: [%s]\n", name, value); }, nullptr, persist); } -/* ************************************************** - * Implementations of functions in resetprop.h (APIs) - * **************************************************/ +struct sysprop { + virtual int setprop(const char *name, const char *value, bool trigger) { return 1; } + virtual string getprop(const char *name, bool persist) { return ""; } + virtual void getprops(void (*callback)(const char *, const char *, void *), + void *cookie, bool persist) {} + virtual int delprop(const char *name, bool persist) { return 1; } +}; -#define ENSURE_INIT(ret) if (init_resetprop()) return ret - -bool prop_exist(const char *name) { - ENSURE_INIT(false); - return __system_property_find(name) != nullptr; -} - -// Get prop by name, return string -string getprop(const char *name, bool persist) { - if (!check_legal_property_name(name)) - return string(); - ENSURE_INIT(string()); - const prop_info *pi = __system_property_find(name); - if (pi == nullptr) { - if (persist && strncmp(name, "persist.", 8) == 0) { - auto value = persist_getprop(name); - if (value.empty()) - goto not_found; - return value; - } -not_found: - LOGD("resetprop: prop [%s] does not exist\n", name); - return string(); - } else { +struct stock_sysprop : public sysprop { + int setprop(const char *name, const char *value, bool) override { + return system_property_set(name, value); + } + string getprop(const char *name, bool) override { char buf[PROP_VALUE_MAX]; - auto reader = make_prop_cb(buf, [](auto, auto value, auto buf) { strcpy(buf, value); }); - read_props(pi, &reader); - LOGD("resetprop: getprop [%s]: [%s]\n", name, buf); + buf[0] = '\0'; + system_property_get(name, buf); return buf; } +}; + +struct resetprop : public sysprop { + int setprop(const char *name, const char *value, bool trigger) override { + if (!check_legal_property_name(name)) + return 1; + + int ret; + auto pi = const_cast(__system_property_find(name)); + if (pi != nullptr) { + if (trigger) { + if (strncmp(name, "ro.", 3) == 0) + delprop(name, false); + ret = system_property_set(name, value); + } else { + ret = __system_property_update(pi, value, strlen(value)); + } + LOGD("resetprop: update prop [%s]: [%s] by %s\n", name, value, + trigger ? "property_service" : "modifying prop data structure"); + } else { + if (trigger) { + ret = system_property_set(name, value); + } else { + ret = __system_property_add(name, strlen(name), value, strlen(value)); + } + LOGD("resetprop: create prop [%s]: [%s] by %s\n", name, value, + trigger ? "property_service" : "modifying prop data structure"); + } + + if (ret) + LOGE("resetprop: setprop error\n"); + + return ret; + } + + string getprop(const char *name, bool persist) override { + if (!check_legal_property_name(name)) + return string(); + auto pi = __system_property_find(name); + if (pi == nullptr) { + if (persist && strncmp(name, "persist.", 8) == 0) { + auto value = persist_getprop(name); + if (value.empty()) + goto not_found; + return value; + } + not_found: + LOGD("resetprop: prop [%s] does not exist\n", name); + return string(); + } else { + string val; + auto reader = make_prop_cb(val, [](auto, auto value, auto str){ str = value; }); + read_prop(pi, &reader); + LOGD("resetprop: getprop [%s]: [%s]\n", name, val.data()); + return val; + } + } + + void getprops(void (*callback)(const char *, const char *, void *), + void *cookie, bool persist) override { + prop_list list; + prop_collector collector(list); + __system_property_foreach(read_prop, &collector); + if (persist) + persist_getprops(&collector); + for (auto &[key, val] : list) + callback(key.data(), val.data(), cookie); + if (persist) + persist_cleanup(); + } + + int delprop(const char *name, bool persist) override { + if (!check_legal_property_name(name)) + return 1; + LOGD("resetprop: delete prop [%s]\n", name); + if (persist && strncmp(name, "persist.", 8) == 0) + persist = persist_deleteprop(name); + return __system_property_delete(name) && !(persist && strncmp(name, "persist.", 8) == 0); + } +}; + +#define DLOAD(name) \ +*(void **) &name = dlsym(RTLD_DEFAULT, "__" #name) + +static sysprop *get_impl() { + static sysprop *impl = nullptr; + if (impl == nullptr) { + use_pb = access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0; +#ifdef APPLET_STUB_MAIN + if (__system_properties_init()) { + LOGE("resetprop: __system_properties_init error\n"); + exit(1); + } + impl = new resetprop(); + system_property_set = &__system_property_set; +#else + DLOAD(system_property_set); /* Always prefer to use setprop from platform */ + if (__system_properties_init()) { + LOGW("resetprop: __system_properties_init error\n"); + DLOAD(system_property_get); + impl = system_property_get ? new stock_sysprop() : new sysprop(); + } else { + impl = new resetprop(); + } +#endif + } + return impl; +} + +/********************************* + * Implementation of public APIs + *********************************/ + +string getprop(const char *name, bool persist) { + return get_impl()->getprop(name, persist); } void getprops(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) { - ENSURE_INIT(); - prop_list list; - prop_collector collector(list); - __system_property_foreach(read_props, &collector); - if (persist) - persist_getprops(&collector); - for (auto &[key, val] : list) - callback(key.data(), val.data(), cookie); - persist_cleanup(); + get_impl()->getprops(callback, cookie, persist); } int setprop(const char *name, const char *value, bool trigger) { - if (!check_legal_property_name(name)) - return 1; - ENSURE_INIT(-1); - - int ret; - - auto pi = (prop_info*) __system_property_find(name); - if (pi != nullptr) { - if (trigger) { - if (strncmp(name, "ro.", 3) == 0) delprop(name); - ret = __system_property_set(name, value); - } else { - ret = __system_property_update(pi, value, strlen(value)); - } - } else { - LOGD("resetprop: New prop [%s]\n", name); - if (trigger) { - ret = __system_property_set(name, value); - } else { - ret = __system_property_add(name, strlen(name), value, strlen(value)); - } - } - - LOGD("resetprop: setprop [%s]: [%s] by %s\n", name, value, - trigger ? "property_service" : "modifing prop data structure"); - - if (ret) - LOGE("resetprop: setprop error\n"); - - return ret; + return get_impl()->setprop(name, value, trigger); } int delprop(const char *name, bool persist) { - if (!check_legal_property_name(name)) - return 1; - ENSURE_INIT(-1); - char path[PATH_MAX]; - path[0] = '\0'; - LOGD("resetprop: delprop [%s]\n", name); - if (persist && strncmp(name, "persist.", 8) == 0) - persist = persist_deleteprop(name); - return __system_property_del(name) && !(persist && strncmp(name, "persist.", 8) == 0); + return get_impl()->delprop(name, persist); } void load_prop_file(const char *filename, bool trigger) { - ENSURE_INIT(); + auto impl = get_impl(); LOGD("resetprop: Parse prop file [%s]\n", filename); parse_prop_file(filename, [=](auto key, auto val) -> bool { - setprop(key.data(), val.data(), trigger); + impl->setprop(key.data(), val.data(), trigger); return true; }); } @@ -253,7 +294,7 @@ int resetprop_main(int argc, char *argv[]) { case 1: prop = getprop(argv[0], persist); if (prop.empty()) return 1; - printf("%s\n", prop.c_str()); + printf("%s\n", prop.data()); return 0; case 2: return setprop(argv[0], argv[1], trigger); diff --git a/native/jni/systemproperties/include/_system_properties.h b/native/jni/systemproperties/include/_system_properties.h index f9a22df83..1cdf77132 100644 --- a/native/jni/systemproperties/include/_system_properties.h +++ b/native/jni/systemproperties/include/_system_properties.h @@ -109,7 +109,7 @@ int __system_property_add(const char* __name, unsigned int __name_length, const ** ** Returns 0 on success, -1 if the property area is full. */ -int __system_property_del(const char *__name); +int __system_property_delete(const char *__name); /* Update the value of a system property returned by ** __system_property_find. Can only be done by a single process diff --git a/native/jni/systemproperties/system_property_api.cpp b/native/jni/systemproperties/system_property_api.cpp index f8656532d..404b36646 100644 --- a/native/jni/systemproperties/system_property_api.cpp +++ b/native/jni/systemproperties/system_property_api.cpp @@ -100,7 +100,7 @@ int __system_property_add(const char* name, unsigned int namelen, const char* va } __BIONIC_WEAK_FOR_NATIVE_BRIDGE -int __system_property_del(const char* name) { +int __system_property_delete(const char* name) { return system_properties.Delete(name); }