Merge "Add CTA 861.3 info to HDR struct"
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 439ab39..7aa94b0 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,7 +58,6 @@
#include "init.h"
#include "persistent_properties.h"
-#include "space_tokenizer.h"
#include "util.h"
using android::base::ReadFileToString;
@@ -69,6 +68,7 @@
using android::base::Trim;
using android::base::WriteStringToFile;
using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
@@ -728,22 +728,6 @@
return 0;
}
-Result<PropertyInfoEntry> ParsePropertyInfoLine(const std::string& line) {
- auto tokenizer = SpaceTokenizer(line);
-
- auto property = tokenizer.GetNext();
- if (property.empty()) return Error() << "Did not find a property entry in '" << line << "'";
-
- auto context = tokenizer.GetNext();
- if (context.empty()) return Error() << "Did not find a context entry in '" << line << "'";
-
- // It is not an error to not find these, as older files will not contain them.
- auto exact_match = tokenizer.GetNext();
- auto schema = tokenizer.GetRemaining();
-
- return {property, context, schema, exact_match == "exact"};
-}
-
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
@@ -752,20 +736,14 @@
return false;
}
- for (const auto& line : Split(file_contents, "\n")) {
- auto trimmed_line = Trim(line);
- if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
- continue;
- }
-
- auto property_info = ParsePropertyInfoLine(line);
- if (!property_info) {
- LOG(ERROR) << "Could not read line from '" << filename << "': " << property_info.error();
- continue;
- }
-
- property_infos->emplace_back(*property_info);
+ auto errors = std::vector<std::string>{};
+ ParsePropertyInfoFile(file_contents, property_infos, &errors);
+ // Individual parsing errors are reported but do not cause a failed boot, which is what
+ // returning false would do here.
+ for (const auto& error : errors) {
+ LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
}
+
return true;
}
diff --git a/init/space_tokenizer.h b/init/space_tokenizer.h
deleted file mode 100644
index e7e22c5..0000000
--- a/init/space_tokenizer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _INIT_SPACE_TOKENIZER_H
-#define _INIT_SPACE_TOKENIZER_H
-
-namespace android {
-namespace init {
-
-class SpaceTokenizer {
- public:
- SpaceTokenizer(const std::string& string)
- : string_(string), it_(string_.begin()), end_(string_.end()) {}
-
- std::string GetNext() {
- auto next = std::string();
- while (it_ != end_ && !isspace(*it_)) {
- next.push_back(*it_++);
- }
- while (it_ != end_ && isspace(*it_)) {
- it_++;
- }
- return next;
- }
-
- std::string GetRemaining() { return std::string(it_, end_); }
-
- private:
- std::string string_;
- std::string::const_iterator it_;
- std::string::const_iterator end_;
-};
-
-} // namespace init
-} // namespace android
-
-#endif
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index fd83ecc..25d3170 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -44,8 +44,6 @@
#define MEMCG_SYSFS_PATH "/dev/memcg/"
#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
-#define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium"
-#define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define LINE_MAX 128
@@ -72,13 +70,22 @@
static int use_inkernel_interface = 1;
static bool has_inkernel_module;
-/* memory pressure level medium event */
-static int mpevfd[2];
-#define CRITICAL_INDEX 1
-#define MEDIUM_INDEX 0
+/* memory pressure levels */
+enum vmpressure_level {
+ VMPRESS_LEVEL_LOW = 0,
+ VMPRESS_LEVEL_MEDIUM,
+ VMPRESS_LEVEL_CRITICAL,
+ VMPRESS_LEVEL_COUNT
+};
-static int medium_oomadj;
-static int critical_oomadj;
+static const char *level_name[] = {
+ "low",
+ "medium",
+ "critical"
+};
+
+static int level_oomadj[VMPRESS_LEVEL_COUNT];
+static int mpevfd[VMPRESS_LEVEL_COUNT];
static bool debug_process_killing;
static bool enable_pressure_upgrade;
static int64_t upgrade_pressure;
@@ -90,8 +97,8 @@
static int ctrl_dfd = -1;
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
-/* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
-#define MAX_EPOLL_EVENTS 4
+/* 3 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
+#define MAX_EPOLL_EVENTS 5
static int epollfd;
static int maxevents;
@@ -226,7 +233,7 @@
return 0;
}
-static void writefilestring(char *path, char *s) {
+static void writefilestring(const char *path, char *s) {
int fd = open(path, O_WRONLY | O_CLOEXEC);
int len = strlen(s);
int ret;
@@ -587,7 +594,8 @@
}
/* Kill one process specified by procp. Returns the size of the process killed */
-static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) {
+static int kill_one_process(struct proc* procp, int min_score_adj,
+ enum vmpressure_level level) {
int pid = procp->pid;
uid_t uid = procp->uid;
char *taskname;
@@ -606,12 +614,12 @@
return -1;
}
+ r = kill(pid, SIGKILL);
ALOGI(
"Killing '%s' (%d), uid %d, adj %d\n"
" to free %ldkB because system is under %s memory pressure oom_adj %d\n",
- taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium",
- min_score_adj);
- r = kill(pid, SIGKILL);
+ taskname, pid, uid, procp->oomadj, tasksize * page_k,
+ level_name[level], min_score_adj);
pid_remove(pid);
if (r) {
@@ -626,10 +634,10 @@
* Find a process to kill based on the current (possibly estimated) free memory
* and cached memory sizes. Returns the size of the killed processes.
*/
-static int find_and_kill_process(bool is_critical) {
+static int find_and_kill_process(enum vmpressure_level level) {
int i;
int killed_size = 0;
- int min_score_adj = is_critical ? critical_oomadj : medium_oomadj;
+ int min_score_adj = level_oomadj[level];
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
@@ -638,7 +646,7 @@
procp = proc_adj_lru(i);
if (procp) {
- killed_size = kill_one_process(procp, min_score_adj, is_critical);
+ killed_size = kill_one_process(procp, min_score_adj, level);
if (killed_size < 0) {
goto retry;
} else {
@@ -674,14 +682,23 @@
return mem_usage;
}
-static void mp_event_common(bool is_critical) {
+enum vmpressure_level upgrade_level(enum vmpressure_level level) {
+ return (enum vmpressure_level)((level < VMPRESS_LEVEL_CRITICAL) ?
+ level + 1 : level);
+}
+
+enum vmpressure_level downgrade_level(enum vmpressure_level level) {
+ return (enum vmpressure_level)((level > VMPRESS_LEVEL_LOW) ?
+ level - 1 : level);
+}
+
+static void mp_event_common(enum vmpressure_level level) {
int ret;
unsigned long long evcount;
- int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
int64_t mem_usage, memsw_usage;
int64_t mem_pressure;
- ret = read(mpevfd[index], &evcount, sizeof(evcount));
+ ret = read(mpevfd[level], &evcount, sizeof(evcount));
if (ret < 0)
ALOGE("Error reading memory pressure event fd; errno=%d",
errno);
@@ -689,18 +706,19 @@
mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
if (memsw_usage < 0 || mem_usage < 0) {
- find_and_kill_process(is_critical);
- return;
+ goto do_kill;
}
// Calculate percent for swappinness.
mem_pressure = (mem_usage * 100) / memsw_usage;
- if (enable_pressure_upgrade && !is_critical) {
+ if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) {
// We are swapping too much.
if (mem_pressure < upgrade_pressure) {
- ALOGI("Event upgraded to critical.");
- is_critical = true;
+ level = upgrade_level(level);
+ if (debug_process_killing) {
+ ALOGI("Event upgraded to %s", level_name[level]);
+ }
}
}
@@ -708,41 +726,51 @@
// kill any process, since enough memory is available.
if (mem_pressure > downgrade_pressure) {
if (debug_process_killing) {
- ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium");
+ ALOGI("Ignore %s memory pressure", level_name[level]);
}
return;
- } else if (is_critical && mem_pressure > upgrade_pressure) {
+ } else if (level == VMPRESS_LEVEL_CRITICAL &&
+ mem_pressure > upgrade_pressure) {
if (debug_process_killing) {
ALOGI("Downgrade critical memory pressure");
}
- // Downgrade event to medium, since enough memory available.
- is_critical = false;
+ // Downgrade event, since enough memory available.
+ level = downgrade_level(level);
}
- if (find_and_kill_process(is_critical) == 0) {
+do_kill:
+ if (find_and_kill_process(level) == 0) {
if (debug_process_killing) {
ALOGI("Nothing to kill");
}
}
}
-static void mp_event(uint32_t events __unused) {
- mp_event_common(false);
+static void mp_event_low(uint32_t events __unused) {
+ mp_event_common(VMPRESS_LEVEL_LOW);
+}
+
+static void mp_event_medium(uint32_t events __unused) {
+ mp_event_common(VMPRESS_LEVEL_MEDIUM);
}
static void mp_event_critical(uint32_t events __unused) {
- mp_event_common(true);
+ mp_event_common(VMPRESS_LEVEL_CRITICAL);
}
-static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
-{
+static bool init_mp_common(void *event_handler, enum vmpressure_level level) {
int mpfd;
int evfd;
int evctlfd;
char buf[256];
struct epoll_event epev;
int ret;
- int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
+ const char *levelstr = level_name[level];
+
+ if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) {
+ ALOGI("%s pressure events are disabled", levelstr);
+ return true;
+ }
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
if (mpfd < 0) {
@@ -783,8 +811,8 @@
goto err;
}
maxevents++;
- mpevfd[mpevfd_index] = evfd;
- return 0;
+ mpevfd[level] = evfd;
+ return true;
err:
close(evfd);
@@ -793,17 +821,7 @@
err_open_evctlfd:
close(mpfd);
err_open_mpfd:
- return -1;
-}
-
-static int init_mp_medium()
-{
- return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false);
-}
-
-static int init_mp_critical()
-{
- return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true);
+ return false;
}
static int init(void) {
@@ -848,10 +866,13 @@
if (use_inkernel_interface) {
ALOGI("Using in-kernel low memory killer interface");
} else {
- ret = init_mp_medium();
- ret |= init_mp_critical();
- if (ret)
+ if (!init_mp_common((void *)&mp_event_low, VMPRESS_LEVEL_LOW) ||
+ !init_mp_common((void *)&mp_event_medium, VMPRESS_LEVEL_MEDIUM) ||
+ !init_mp_common((void *)&mp_event_critical,
+ VMPRESS_LEVEL_CRITICAL)) {
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
+ return -1;
+ }
}
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
@@ -892,8 +913,13 @@
.sched_priority = 1,
};
- medium_oomadj = property_get_int32("ro.lmk.medium", 800);
- critical_oomadj = property_get_int32("ro.lmk.critical", 0);
+ /* By default disable low level vmpressure events */
+ level_oomadj[VMPRESS_LEVEL_LOW] =
+ property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1);
+ level_oomadj[VMPRESS_LEVEL_MEDIUM] =
+ property_get_int32("ro.lmk.medium", 800);
+ level_oomadj[VMPRESS_LEVEL_CRITICAL] =
+ property_get_int32("ro.lmk.critical", 0);
debug_process_killing = property_get_bool("ro.lmk.debug", false);
enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false);
upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50);
diff --git a/property_service/OWNERS b/property_service/OWNERS
new file mode 100644
index 0000000..babbe4d
--- /dev/null
+++ b/property_service/OWNERS
@@ -0,0 +1 @@
+tomcherry@google.com
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 3e732b5..c046417 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -1,5 +1,6 @@
cc_library_static {
name: "libpropertyinfoparser",
+ host_supported: true,
srcs: ["property_info_parser.cpp"],
cpp_std: "experimental",
diff --git a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
index 8c3507e..2ee8161 100644
--- a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
+++ b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
@@ -18,6 +18,7 @@
#define PROPERTY_INFO_PARSER_H
#include <stdint.h>
+#include <stdlib.h>
namespace android {
namespace properties {
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 20e5e13..bc28e82 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -1,5 +1,6 @@
cc_defaults {
name: "propertyinfoserializer_defaults",
+ host_supported: true,
cpp_std: "experimental",
sanitize: {
misc_undefined: ["signed-integer-overflow"],
@@ -19,6 +20,7 @@
name: "libpropertyinfoserializer",
defaults: ["propertyinfoserializer_defaults"],
srcs: [
+ "property_info_file.cpp",
"property_info_serializer.cpp",
"trie_builder.cpp",
"trie_serializer.cpp",
diff --git a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
index f7e708e..d2ec385 100644
--- a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
+++ b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
@@ -41,6 +41,10 @@
const std::string& default_context, const std::string& default_schema,
std::string* serialized_trie, std::string* error);
+void ParsePropertyInfoFile(const std::string& file_contents,
+ std::vector<PropertyInfoEntry>* property_infos,
+ std::vector<std::string>* errors);
+
} // namespace properties
} // namespace android
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
new file mode 100644
index 0000000..702f219
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -0,0 +1,62 @@
+#include <property_info_serializer/property_info_serializer.h>
+
+#include <android-base/strings.h>
+
+#include "space_tokenizer.h"
+
+using android::base::Split;
+using android::base::StartsWith;
+using android::base::Trim;
+
+namespace android {
+namespace properties {
+
+bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
+ auto tokenizer = SpaceTokenizer(line);
+
+ auto property = tokenizer.GetNext();
+ if (property.empty()) {
+ *error = "Did not find a property entry in '" + line + "'";
+ return false;
+ }
+
+ auto context = tokenizer.GetNext();
+ if (context.empty()) {
+ *error = "Did not find a context entry in '" + line + "'";
+ return false;
+ }
+
+ // It is not an error to not find these, as older files will not contain them.
+ auto exact_match = tokenizer.GetNext();
+ auto schema = tokenizer.GetRemaining();
+
+ *out = {property, context, schema, exact_match == "exact"};
+ return true;
+}
+
+void ParsePropertyInfoFile(const std::string& file_contents,
+ std::vector<PropertyInfoEntry>* property_infos,
+ std::vector<std::string>* errors) {
+ // Do not clear property_infos to allow this function to be called on multiple files, with
+ // their results concatenated.
+ errors->clear();
+
+ for (const auto& line : Split(file_contents, "\n")) {
+ auto trimmed_line = Trim(line);
+ if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
+ continue;
+ }
+
+ auto property_info_entry = PropertyInfoEntry{};
+ auto parse_error = std::string{};
+ if (!ParsePropertyInfoLine(trimmed_line, &property_info_entry, &parse_error)) {
+ errors->emplace_back(parse_error);
+ continue;
+ }
+
+ property_infos->emplace_back(property_info_entry);
+ }
+}
+
+} // namespace properties
+} // namespace android
diff --git a/property_service/libpropertyinfoserializer/space_tokenizer.h b/property_service/libpropertyinfoserializer/space_tokenizer.h
new file mode 100644
index 0000000..fba0c58
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/space_tokenizer.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H
+#define PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H
+
+namespace android {
+namespace properties {
+
+class SpaceTokenizer {
+ public:
+ SpaceTokenizer(const std::string& string)
+ : string_(string), it_(string_.begin()), end_(string_.end()) {}
+
+ std::string GetNext() {
+ auto next = std::string();
+ while (it_ != end_ && !isspace(*it_)) {
+ next.push_back(*it_++);
+ }
+ while (it_ != end_ && isspace(*it_)) {
+ it_++;
+ }
+ return next;
+ }
+
+ std::string GetRemaining() { return std::string(it_, end_); }
+
+ private:
+ std::string string_;
+ std::string::const_iterator it_;
+ std::string::const_iterator end_;
+};
+
+} // namespace properties
+} // namespace android
+
+#endif
diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp
new file mode 100644
index 0000000..2c9a2ba
--- /dev/null
+++ b/property_service/property_info_checker/Android.bp
@@ -0,0 +1,14 @@
+cc_binary {
+ name: "property_info_checker",
+ host_supported: true,
+ cpp_std: "experimental",
+ sanitize: {
+ misc_undefined: ["signed-integer-overflow"],
+ },
+ static_libs: [
+ "libpropertyinfoserializer",
+ "libpropertyinfoparser",
+ "libbase",
+ ],
+ srcs: ["property_info_checker.cpp"],
+}
\ No newline at end of file
diff --git a/property_service/property_info_checker/property_info_checker.cpp b/property_service/property_info_checker/property_info_checker.cpp
new file mode 100644
index 0000000..e4f8264
--- /dev/null
+++ b/property_service/property_info_checker/property_info_checker.cpp
@@ -0,0 +1,51 @@
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+
+#include <property_info_serializer/property_info_serializer.h>
+
+using android::base::ReadFileToString;
+using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
+using android::properties::PropertyInfoEntry;
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ std::cerr << "A list of property info files to be checked is expected on the command line"
+ << std::endl;
+ return -1;
+ }
+
+ auto property_info_entries = std::vector<PropertyInfoEntry>{};
+
+ for (int i = 1; i < argc; ++i) {
+ auto filename = argv[i];
+ auto file_contents = std::string{};
+ if (!ReadFileToString(filename, &file_contents)) {
+ std::cerr << "Could not read properties from '" << filename << "'" << std::endl;
+ return -1;
+ }
+
+ auto errors = std::vector<std::string>{};
+ ParsePropertyInfoFile(file_contents, &property_info_entries, &errors);
+ if (!errors.empty()) {
+ for (const auto& error : errors) {
+ std::cerr << "Could not read line from '" << filename << "': " << error << std::endl;
+ }
+ return -1;
+ }
+ }
+
+ auto serialized_contexts = std::string{};
+ auto build_trie_error = std::string{};
+
+ if (!BuildTrie(property_info_entries, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
+ &build_trie_error)) {
+ std::cerr << "Unable to serialize property contexts: " << build_trie_error << std::endl;
+ return -1;
+ }
+
+ return 0;
+}