From aa8b23105f66a460f8f996c7015d4c0f22b743ff Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 7 May 2020 06:08:30 -0700 Subject: [PATCH] Modernize resetprop with fancy C++ --- native/jni/include/resetprop.hpp | 5 +- native/jni/resetprop/_resetprop.hpp | 80 +++++++-------- native/jni/resetprop/persist_properties.cpp | 74 ++++++++------ native/jni/resetprop/resetprop.cpp | 104 +++++++++----------- 4 files changed, 129 insertions(+), 134 deletions(-) diff --git a/native/jni/include/resetprop.hpp b/native/jni/include/resetprop.hpp index 93f0a0a62..12b272ede 100644 --- a/native/jni/include/resetprop.hpp +++ b/native/jni/include/resetprop.hpp @@ -3,9 +3,10 @@ #include #include -int prop_exist(const char *name); +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 getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist = false); +void getprops(void (*callback)(const char *, const char *, void *), + void *cookie = nullptr, bool persist = false); int delprop(const char *name, bool persist = false); void load_prop_file(const char *filename, bool trigger = true); diff --git a/native/jni/resetprop/_resetprop.hpp b/native/jni/resetprop/_resetprop.hpp index dc24f07a6..6d8b3459f 100644 --- a/native/jni/resetprop/_resetprop.hpp +++ b/native/jni/resetprop/_resetprop.hpp @@ -1,57 +1,49 @@ #pragma once #include +#include #include #include -struct prop_t { - char *name; - char value[PROP_VALUE_MAX]; - prop_t() : name(nullptr) {} - explicit prop_t(const char *name) { - this->name = strdup(name); - value[0] = '\0'; - } - prop_t(const char *name, const char *value) { - this->name = strdup(name); - strcpy(this->value, value); - } - prop_t(prop_t &&prop): name(nullptr) { - operator=(std::move(prop)); - } - bool operator<(const prop_t &prop) const { - return strcmp(name, prop.name) < 0; - } - prop_t& operator=(prop_t &&prop) { - if (this != &prop) { - free(name); - name = prop.name; - strcpy(value, prop.value); - prop.name = nullptr; - } - return *this; - }; - ~prop_t() { - free(name); - } -}; - -struct read_cb_t { - void (*cb)(const char *, const char *, void *); - void *arg; - explicit read_cb_t(void (*cb)(const char *, const char *, void *) = nullptr, void *arg = nullptr) - : cb(cb), arg(arg) {} - void exec(const char *name, const char *value) { - cb(name, value, arg); - } -}; - #define PERSISTENT_PROPERTY_DIR "/data/property" +struct prop_cb { + virtual void exec(const char *name, const char *value) = 0; +}; + +template +struct prop_cb_impl : public prop_cb { + typedef void (*callback_type)(const char *, const char *, T&); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-field" // Dangling field is expected + prop_cb_impl(T &arg, callback_type fn) : arg(arg), fn(fn) {} +#pragma GCC diagnostic pop + + void exec(const char *name, const char *value) override { + fn(name, value, arg); + } +private: + T &arg; + callback_type fn; +}; + extern bool use_pb; +using prop_list = std::map; + +struct prop_collector : prop_cb_impl { + prop_collector(prop_list &list) : + prop_cb_impl(list, [](auto name, auto val, auto list){ list.emplace(name, val); }) {} +}; + +template +prop_cb_impl make_prop_cb(T &arg, Func f) { + return prop_cb_impl(arg, f); +} + std::string persist_getprop(const char *name); -void persist_getprop(read_cb_t *read_cb); +void persist_getprops(prop_cb *prop_cb); bool persist_deleteprop(const char *name); -void collect_props(const char *name, const char *value, void *v_plist); +void persist_cleanup(); diff --git a/native/jni/resetprop/persist_properties.cpp b/native/jni/resetprop/persist_properties.cpp index c38974c20..b5d0b5b0c 100644 --- a/native/jni/resetprop/persist_properties.cpp +++ b/native/jni/resetprop/persist_properties.cpp @@ -88,8 +88,22 @@ const pb_field_t PersistentProperties_fields[2] = { * End of auto generated code * ***************************/ +#ifdef APPLET_STUB_MAIN +struct { + void push_back(...){}; +} allocs; +void persist_cleanup(){} +#else +static thread_local vector allocs; +void persist_cleanup() { + std::for_each(allocs.begin(), allocs.end(), [](auto p){ free(p); }); + allocs.clear(); +} +#endif + static bool name_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) { - auto name = new pb_byte_t[stream->bytes_left + 1]; + auto name = (pb_byte_t *) malloc(stream->bytes_left + 1); + allocs.push_back(name); /* Record all mallocs to cleanup */ name[stream->bytes_left] = '\0'; if (!pb_read(stream, name, stream->bytes_left)) return false; @@ -107,8 +121,7 @@ static bool prop_decode(pb_istream_t *stream, const pb_field_t *field, void **ar prop.name.funcs.decode = name_decode; if (!pb_decode(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop)) return false; - ((read_cb_t *) *arg)->exec((const char *) prop.name.arg, prop.value); - delete[] (pb_byte_t *) prop.name.arg; + reinterpret_cast(*arg)->exec((const char *) prop.name.arg, prop.value); return true; } @@ -116,12 +129,12 @@ static bool prop_encode(pb_ostream_t *stream, const pb_field_t *field, void * co PersistentProperties_PersistentPropertyRecord prop = {}; prop.name.funcs.encode = name_encode; prop.has_value = true; - auto &prop_list = *(vector *) *arg; - for (auto &p : prop_list) { + auto &list = *(prop_list *) *arg; + for (auto &p : list) { if (!pb_encode_tag_for_field(stream, field)) return false; - prop.name.arg = p.name; - strcpy(prop.value, p.value); + prop.name.arg = (void *) p.first.data(); + strcpy(prop.value, p.second.data()); if (!pb_encode_submessage(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop)) return false; } @@ -144,17 +157,11 @@ static pb_ostream_t create_ostream(const char *filename) { return o; } -static void pb_getprop_cb(const char *name, const char *value, void *v) { - struct prop_t *prop = static_cast(v); - if (prop->name && strcmp(name, prop->name) == 0) - strcpy(prop->value, value); -} - -static void pb_getprop(read_cb_t *read_cb) { +static void pb_getprop(prop_cb *prop_cb) { LOGD("resetprop: decode with protobuf [" PERSISTENT_PROPERTY_DIR "/persistent_properties]\n"); PersistentProperties props = {}; props.properties.funcs.decode = prop_decode; - props.properties.arg = read_cb; + props.properties.arg = prop_cb; pb_byte_t *buf; size_t size; mmap_ro(PERSISTENT_PROPERTY_DIR "/persistent_properties", buf, size); @@ -175,9 +182,9 @@ static bool file_getprop(const char *name, char *value) { return value[0] != '\0'; } -void persist_getprop(read_cb_t *read_cb) { +void persist_getprops(prop_cb *prop_cb) { if (use_pb) { - pb_getprop(read_cb); + pb_getprop(prop_cb); } else { DIR *dir = opendir(PERSISTENT_PROPERTY_DIR); struct dirent *entry; @@ -186,16 +193,25 @@ void persist_getprop(read_cb_t *read_cb) { continue; char value[PROP_VALUE_MAX]; if (file_getprop(entry->d_name, value)) - read_cb->exec(entry->d_name, value); + prop_cb->exec(entry->d_name, value); } } } string persist_getprop(const char *name) { - prop_t prop(name); if (use_pb) { - read_cb_t read_cb(pb_getprop_cb, &prop); - pb_getprop(&read_cb); + run_finally f([]{ persist_cleanup(); }); + struct { + const char *name; + char value[PROP_VALUE_MAX]; + } prop; + prop.name = name; + prop.value[0] = '\0'; + auto reader = make_prop_cb(prop, [](auto name, auto value, auto prop) { + if (strcmp(name, prop.name) == 0) + strcpy(prop.value, value); + }); + pb_getprop(&reader); if (prop.value[0]) return prop.value; } else { @@ -209,19 +225,20 @@ string persist_getprop(const char *name) { bool persist_deleteprop(const char *name) { if (use_pb) { - vector prop_list; - read_cb_t read_cb(collect_props, &prop_list); - persist_getprop(&read_cb); + run_finally f([]{ persist_cleanup(); }); + prop_list list; + prop_collector collector(list); + persist_getprops(&collector); - for (auto it = prop_list.begin(); it != prop_list.end(); ++it) { - if (strcmp(it->name, name) == 0) { - prop_list.erase(it); + for (auto it = list.begin(); it != list.end(); ++it) { + if (it->first == name) { + list.erase(it); // Dump the props back PersistentProperties props = PersistentProperties_init_zero; pb_ostream_t ostream = create_ostream(PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp"); props.properties.funcs.encode = prop_encode; - props.properties.arg = &prop_list; + props.properties.arg = &list; LOGD("resetprop: encode with protobuf [" PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp]\n"); if (!pb_encode(&ostream, PersistentProperties_fields, &props)) @@ -233,7 +250,6 @@ bool persist_deleteprop(const char *name) { return true; } } - return false; } else { char path[PATH_MAX]; diff --git a/native/jni/resetprop/resetprop.cpp b/native/jni/resetprop/resetprop.cpp index 51e2a6eb1..dcf0ed642 100644 --- a/native/jni/resetprop/resetprop.cpp +++ b/native/jni/resetprop/resetprop.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -55,48 +55,34 @@ illegal: [[noreturn]] static void usage(char* arg0) { fprintf(stderr, - NAME_WITH_VER(resetprop) " - System Props Modification Tool\n\n" - "Usage: %s [flags] [options...]\n" - "\n" - "Options:\n" - " -h, --help show this message\n" - " (no arguments) print all properties\n" - " NAME get property\n" - " NAME VALUE set property entry NAME with VALUE\n" - " --file FILE load props from FILE\n" - " --delete NAME delete property\n" - "\n" - "Flags:\n" - " -v print verbose output to stderr\n" - " -n set properties without init triggers\n" - " only affects setprop\n" - " -p access actual persist storage\n" - " only affects getprop and delprop\n" - "\n" +NAME_WITH_VER(resetprop) R"EOF(" - System Props Modification Tool - , arg0); +Usage: %s [flags] [options...] + +Options: + -h, --help show this message + (no arguments) print all properties + NAME get property + NAME VALUE set property entry NAME with VALUE + --file FILE load props from FILE + --delete NAME delete property + +Flags: + -v print verbose output to stderr + -n set properties without going through init + affects setprop and prop file loading + -p also access props directly from persist storage + affects getprop and delprop + +)EOF", arg0); exit(1); } -static void read_props(const prop_info *pi, void *read_cb) { +static void read_props(const prop_info *pi, void *cb) { __system_property_read_callback( pi, [](auto cb, auto name, auto value, auto) { - ((read_cb_t *) cb)->exec(name, value); - }, read_cb); -} - -void collect_props(const char *name, const char *value, void *v_plist) { - auto prop_list = static_cast *>(v_plist); - prop_list->emplace_back(name, value); -} - -static void collect_unique_props(const char *name, const char *value, void *v_plist) { - auto &prop_list = *static_cast *>(v_plist); - for (auto &prop : prop_list) { - if (strcmp(name, prop.name) == 0) - return; - } - collect_props(name, value, v_plist); + reinterpret_cast(cb)->exec(name, value); + }, cb); } static int init_resetprop() { @@ -109,11 +95,9 @@ static int init_resetprop() { } static void print_props(bool persist) { - vector prop_list; - getprop(collect_props, &prop_list, persist); - sort(prop_list.begin(), prop_list.end()); - for (auto &prop : prop_list) - printf("[%s]: [%s]\n", prop.name, prop.value); + getprops([](auto name, auto value, auto) { + printf("[%s]: [%s]\n", name, value); + }, nullptr, persist); } /* ************************************************** @@ -122,8 +106,8 @@ static void print_props(bool persist) { #define ENSURE_INIT(ret) if (init_resetprop()) return ret -int prop_exist(const char *name) { - ENSURE_INIT(0); +bool prop_exist(const char *name) { + ENSURE_INIT(false); return __system_property_find(name) != nullptr; } @@ -137,29 +121,31 @@ string getprop(const char *name, bool persist) { if (persist && strncmp(name, "persist.", 8) == 0) { auto value = persist_getprop(name); if (value.empty()) - LOGD("resetprop: prop [%s] does not exist\n", name); + goto not_found; return value; } +not_found: + LOGD("resetprop: prop [%s] does not exist\n", name); return string(); } else { - char value[PROP_VALUE_MAX]; - read_cb_t read_cb; - read_cb.cb = [](auto, auto value, auto dst) -> void { strcpy((char *) dst, value); }; - read_cb.arg = value; - read_props(pi, &read_cb); - LOGD("resetprop: getprop [%s]: [%s]\n", name, value); - return value; + 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); + return buf; } } -void getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) { +void getprops(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) { ENSURE_INIT(); - read_cb_t read_cb(callback, cookie); - __system_property_foreach(read_props, &read_cb); - if (persist) { - read_cb.cb = collect_unique_props; - persist_getprop(&read_cb); - } + 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(); } int setprop(const char *name, const char *value, bool trigger) {