Merge "fs_mgr: Small fix in overlayfs setup/teardown" am: 5f42ee186d am: 06c8fb2569 am: 7b5a663844
am: 82265c5d7e
Change-Id: Id03f682dd08cf762461670228a1ff82a1a85e9cf
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index a14d0e5..3b45db7 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -755,24 +755,31 @@
}
static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
- FILE *fp;
- char buf[PATH_MAX];
+ FILE *fp;
+ char buf[PATH_MAX];
- snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
+ /*
+ * Per-application memory.stat files are available only when
+ * per-application memcgs are enabled.
+ */
+ if (!per_app_memcg)
+ return -1;
- fp = fopen(buf, "r");
+ snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
- if (fp == NULL) {
- ALOGE("%s open failed: %s", buf, strerror(errno));
- return -1;
- }
+ fp = fopen(buf, "r");
- while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
- memory_stat_parse_line(buf, mem_st);
- }
- fclose(fp);
+ if (fp == NULL) {
+ ALOGE("%s open failed: %s", buf, strerror(errno));
+ return -1;
+ }
- return 0;
+ while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
+ memory_stat_parse_line(buf, mem_st);
+ }
+ fclose(fp);
+
+ return 0;
}
#endif
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3a6a5e8..0312859 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -162,66 +162,6 @@
)
endef
-# Update namespace configuration file with library lists and VNDK version
-#
-# $(1): Input source file (ld.config.txt)
-# $(2): Output built module
-# $(3): VNDK version suffix
-# $(4): true if libz must be included in llndk not in vndk-sp
-define update_and_install_ld_config
-# If $(4) is true, move libz to llndk from vndk-sp.
-$(if $(filter true,$(4)),\
- $(eval llndk_libraries_list := $(LLNDK_LIBRARIES) libz) \
- $(eval vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))),\
- $(eval llndk_libraries_list := $(LLNDK_LIBRARIES)) \
- $(eval vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)))
-
-llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
-private_llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
-vndk_sameprocess_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(vndksp_libraries_list))))
-vndk_core_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
- $(UBSAN_RUNTIME_LIBRARY) \
- $(TSAN_RUNTIME_LIBRARY) \
- $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
- $(2ND_UBSAN_RUNTIME_LIBRARY) \
- $(2ND_TSAN_RUNTIME_LIBRARY)))
-# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used.
-vndk_version_suffix := $(if $(strip $(3)),-$(strip $(3)))
-
-$(2): PRIVATE_LLNDK_LIBRARIES := $$(llndk_libraries)
-$(2): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $$(private_llndk_libraries)
-$(2): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $$(vndk_sameprocess_libraries)
-$(2): PRIVATE_VNDK_CORE_LIBRARIES := $$(vndk_core_libraries)
-$(2): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $$(sanitizer_runtime_libraries)
-$(2): PRIVATE_VNDK_VERSION := $$(vndk_version_suffix)
-$(2): $(1)
- @echo "Generate: $$< -> $$@"
- @mkdir -p $$(dir $$@)
- $$(hide) sed -e 's?%LLNDK_LIBRARIES%?$$(PRIVATE_LLNDK_LIBRARIES)?g' $$< >$$@
- $$(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $$@
- $$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $$@
- $$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $$@
- $$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@
- $$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@
- $$(hide) sed -i -e 's?%PRODUCT%?$$(TARGET_COPY_OUT_PRODUCT)?g' $$@
- $$(hide) sed -i -e 's?%PRODUCTSERVICES%?$$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $$@
-
-llndk_libraries_list :=
-vndksp_libraries_list :=
-llndk_libraries :=
-private_llndk_libraries :=
-vndk_sameprocess_libraries :=
-vndk_core_libraries :=
-sanitizer_runtime_libraries :=
-vndk_version_suffix :=
-endef # update_and_install_ld_config
-
#######################################
# ld.config.txt selection variables
@@ -265,21 +205,19 @@
# for VNDK enforced devices
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt,\
- $(LOCAL_BUILT_MODULE),\
- $(PLATFORM_VNDK_VERSION)))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
else ifeq ($(_enforce_vndk_lite_at_runtime),true)
# for treblized but VNDK lightly enforced devices
LOCAL_MODULE_STEM := ld.config.vndk_lite.txt
include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
- $(LOCAL_BUILT_MODULE),\
- $(PLATFORM_VNDK_VERSION),\
- true))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+libz_is_llndk := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
else
@@ -290,6 +228,31 @@
endif # ifeq ($(_enforce_vndk_at_runtime),true)
+# ld.config.txt for VNDK versions older than PLATFORM_VNDK_VERSION
+# are built with the VNDK libraries lists under /prebuilts/vndk.
+#
+# ld.config.$(VER).txt is built and installed for all VNDK versions
+# listed in PRODUCT_EXTRA_VNDK_VERSIONS.
+#
+# $(1): VNDK version
+define build_versioned_ld_config
+include $(CLEAR_VARS)
+LOCAL_MODULE := ld.config.$(1).txt
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $$(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt
+vndk_version := $(1)
+lib_list_from_prebuilts := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
+endef
+
+# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the
+# prebuilt under /prebuilts/vndk
+supported_vndk_snapshot_versions := 28
+$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\
+ $(call build_versioned_ld_config,$(ver))))
#######################################
# ld.config.vndk_lite.txt
@@ -304,11 +267,10 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
- $(LOCAL_BUILT_MODULE),\
- $(PLATFORM_VNDK_VERSION),\
- true))
+ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
+vndk_version := $(PLATFORM_VNDK_VERSION)
+libz_is_llndk := true
+include $(LOCAL_PATH)/update_and_install_ld_config.mk
endif # ifeq ($(_enforce_vndk_lite_at_runtime),false)
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index e20b95d..2a51d53 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,6 +1,7 @@
# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
libandroid.so
libaaudio.so
+libamidi.so
libc.so
libcamera2ndk.so
libdl.so
diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt
index ff0813d..6690770 100644
--- a/rootdir/etc/public.libraries.iot.txt
+++ b/rootdir/etc/public.libraries.iot.txt
@@ -2,6 +2,7 @@
libandroid.so
libandroidthings.so
libaaudio.so
+libamidi.so
libc.so
libcamera2ndk.so
libdl.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 3c46094..56055ba 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,6 +1,7 @@
# See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md
libandroid.so
libaaudio.so
+libamidi.so
libc.so
libcamera2ndk.so
libdl.so
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
new file mode 100644
index 0000000..06e04e7
--- /dev/null
+++ b/rootdir/update_and_install_ld_config.mk
@@ -0,0 +1,123 @@
+#####################################################################
+# Builds linker config file, ld.config.txt, from the specified template
+# under $(LOCAL_PATH)/etc/*.
+#
+# Inputs:
+# (expected to follow an include of $(BUILD_SYSTEM)/base_rules.mk)
+# ld_config_template: template linker config file to use,
+# e.g. $(LOCAL_PATH)/etc/ld.config.txt
+# vndk_version: version of the VNDK library lists used to update the
+# template linker config file, e.g. 28
+# lib_list_from_prebuilts: should be set to 'true' if the VNDK library
+# lists should be read from /prebuilts/vndk/*
+# libz_is_llndk: should be set to 'true' if libz must be included in
+# llndk and not in vndk-sp
+# Outputs:
+# Builds and installs ld.config.$VER.txt or ld.config.vndk_lite.txt
+#####################################################################
+
+# Read inputs
+ld_config_template := $(strip $(ld_config_template))
+vndk_version := $(strip $(vndk_version))
+lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts))
+libz_is_llndk := $(strip $(libz_is_llndk))
+
+intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE))
+library_lists_dir := $(intermediates_dir)
+ifeq ($(lib_list_from_prebuilts),true)
+ library_lists_dir := prebuilts/vndk/v$(vndk_version)/$(TARGET_ARCH)/configs
+endif
+
+llndk_libraries_file := $(library_lists_dir)/llndk.libraries.$(vndk_version).txt
+vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
+vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
+vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+ $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(UBSAN_RUNTIME_LIBRARY) \
+ $(TSAN_RUNTIME_LIBRARY) \
+ $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+ $(2ND_UBSAN_RUNTIME_LIBRARY) \
+ $(2ND_TSAN_RUNTIME_LIBRARY)))
+# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used.
+vndk_version_suffix := $(if $(vndk_version),-$(vndk_version))
+
+ifneq ($(lib_list_from_prebuilts),true)
+ifeq ($(libz_is_llndk),true)
+ llndk_libraries_list := $(LLNDK_LIBRARIES) libz
+ vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))
+else
+ llndk_libraries_list := $(LLNDK_LIBRARIES)
+ vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)
+endif
+
+# $(1): list of libraries
+# $(2): output file to write the list of libraries to
+define write-libs-to-file
+$(2): PRIVATE_LIBRARIES := $(1)
+$(2):
+ echo -n > $$@ && $$(foreach lib,$$(PRIVATE_LIBRARIES),echo $$(lib).so >> $$@;)
+endef
+$(eval $(call write-libs-to-file,$(llndk_libraries_list),$(llndk_libraries_file)))
+$(eval $(call write-libs-to-file,$(vndksp_libraries_list),$(vndksp_libraries_file)))
+$(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),$(vndkcore_libraries_file)))
+$(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),$(vndkprivate_libraries_file)))
+endif # ifneq ($(lib_list_from_prebuilts),true)
+
+# Given a file with a list of libs, filter-out the VNDK private libraries
+# and write resulting list to a new file in "a:b:c" format
+#
+# $(1): libs file from which to filter-out VNDK private libraries
+# $(2): output file with the filtered list of lib names
+$(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \
+ paste -sd ":" $(1) > $(2) && \
+ cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i 's/privatelib//' $(2)" && \
+ sed -i -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2)
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE := $(vndkprivate_libraries_file)
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
+$(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
+deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
+ $(vndkprivate_libraries_file)
+
+$(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps)
+ @echo "Generate: $< -> $@"
+ @mkdir -p $(dir $@)
+ $(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
+ $(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@
+ $(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)
+ $(hide) sed -i -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@
+ $(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)
+ $(hide) sed -i -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@
+
+ $(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
+ cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \
+ xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \
+ paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
+ sed -i -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
+
+ $(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
+ $(hide) sed -i -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@
+ $(hide) sed -i -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@
+ $(hide) sed -i -e 's?%PRODUCTSERVICES%?$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $@
+
+ld_config_template :=
+vndk_version :=
+lib_list_from_prebuilts :=
+libz_is_llndk :=
+intermediates_dir :=
+library_lists_dir :=
+llndk_libraries_file :=
+vndksp_libraries_file :=
+vndkcore_libraries_file :=
+vndkprivate_libraries_file :=
+deps :=
+sanitizer_runtime_libraries :=
+vndk_version_suffix :=
+llndk_libraries_list :=
+vndksp_libraries_list :=
+write-libs-to-file :=
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index 3a718fa..fffb3d2 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -68,31 +68,33 @@
struct uid_record {
string name;
- struct uid_io_usage ios;
+ uid_io_usage ios;
};
struct uid_records {
uint64_t start_ts;
- vector<struct uid_record> entries;
+ vector<uid_record> entries;
};
class uid_monitor {
private:
FRIEND_TEST(storaged_test, uid_monitor);
+ FRIEND_TEST(storaged_test, load_uid_io_proto);
+
// last dump from /proc/uid_io/stats, uid -> uid_info
- unordered_map<uint32_t, uid_info> last_uid_io_stats;
+ unordered_map<uint32_t, uid_info> last_uid_io_stats_;
// current io usage for next report, app name -> uid_io_usage
- unordered_map<string, struct uid_io_usage> curr_io_stats;
+ unordered_map<string, uid_io_usage> curr_io_stats_;
// io usage records, end timestamp -> {start timestamp, vector of records}
- map<uint64_t, struct uid_records> io_history;
+ map<uint64_t, uid_records> io_history_;
// charger ON/OFF
- charger_stat_t charger_stat;
+ charger_stat_t charger_stat_;
// protects curr_io_stats, last_uid_io_stats, records and charger_stat
- Mutex uidm_mutex;
+ Mutex uidm_mutex_;
// start time for IO records
- uint64_t start_ts;
+ uint64_t start_ts_;
// true if UID_IO_STATS_PATH is accessible
- const bool enable;
+ const bool enabled_;
// reads from /proc/uid_io/stats
unordered_map<uint32_t, uid_info> get_uid_io_stats_locked();
@@ -103,6 +105,10 @@
// writes io_history to protobuf
void update_uid_io_proto(unordered_map<int, StoragedProto>* protos);
+ // Ensure that io_history_ can append |n| items without exceeding
+ // MAX_UID_RECORDS_SIZE in size.
+ void maybe_shrink_history_for_items(size_t nitems);
+
public:
uid_monitor();
// called by storaged main thread
@@ -110,16 +116,20 @@
// called by storaged -u
unordered_map<uint32_t, uid_info> get_uid_io_stats();
// called by dumpsys
- map<uint64_t, struct uid_records> dump(
+ map<uint64_t, uid_records> dump(
double hours, uint64_t threshold, bool force_report);
// called by battery properties listener
void set_charger_state(charger_stat_t stat);
// called by storaged periodic_chore or dump with force_report
- bool enabled() { return enable; };
+ bool enabled() { return enabled_; };
void report(unordered_map<int, StoragedProto>* protos);
// restores io_history from protobuf
- void load_uid_io_proto(const UidIOUsage& proto);
+ void load_uid_io_proto(userid_t user_id, const UidIOUsage& proto);
void clear_user_history(userid_t user_id);
+
+ map<uint64_t, uid_records>& io_history() { return io_history_; }
+
+ static constexpr int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
};
#endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index f346c38..77c6167 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -194,7 +194,7 @@
return;
}
- mUidm.load_uid_io_proto(proto.uid_io_usage());
+ mUidm.load_uid_io_proto(user_id, proto.uid_io_usage());
if (user_id == USER_SYSTEM) {
storage_info->load_perf_history_proto(proto.perf_history());
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 5745782..55380ba 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <android/content/pm/IPackageManagerNative.h>
#include <android-base/file.h>
@@ -50,7 +51,7 @@
std::unordered_map<uint32_t, uid_info> uid_monitor::get_uid_io_stats()
{
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
return get_uid_io_stats_locked();
};
@@ -178,10 +179,10 @@
uid_io_stats[u.uid].name = std::to_string(u.uid);
uids.push_back(u.uid);
uid_names.push_back(&uid_io_stats[u.uid].name);
- if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
+ if (last_uid_io_stats_.find(u.uid) == last_uid_io_stats_.end()) {
refresh_uid_names = true;
} else {
- uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name;
+ uid_io_stats[u.uid].name = last_uid_io_stats_[u.uid].name;
}
} else {
task_info t;
@@ -200,8 +201,6 @@
namespace {
-const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
-
inline size_t history_size(
const std::map<uint64_t, struct uid_records>& history)
{
@@ -218,12 +217,12 @@
{
// remove records more than 5 days old
if (curr_ts > 5 * DAY_TO_SEC) {
- auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC);
- io_history.erase(io_history.begin(), it);
+ auto it = io_history_.lower_bound(curr_ts - 5 * DAY_TO_SEC);
+ io_history_.erase(io_history_.begin(), it);
}
struct uid_records new_records;
- for (const auto& p : curr_io_stats) {
+ for (const auto& p : curr_io_stats_) {
struct uid_record record = {};
record.name = p.first;
if (!p.second.uid_ios.is_zero()) {
@@ -237,23 +236,26 @@
}
}
- curr_io_stats.clear();
- new_records.start_ts = start_ts;
- start_ts = curr_ts;
+ curr_io_stats_.clear();
+ new_records.start_ts = start_ts_;
+ start_ts_ = curr_ts;
if (new_records.entries.empty())
return;
// make some room for new records
- ssize_t overflow = history_size(io_history) +
- new_records.entries.size() - MAX_UID_RECORDS_SIZE;
- while (overflow > 0 && io_history.size() > 0) {
- auto del_it = io_history.begin();
- overflow -= del_it->second.entries.size();
- io_history.erase(io_history.begin());
- }
+ maybe_shrink_history_for_items(new_records.entries.size());
- io_history[curr_ts] = new_records;
+ io_history_[curr_ts] = new_records;
+}
+
+void uid_monitor::maybe_shrink_history_for_items(size_t nitems) {
+ ssize_t overflow = history_size(io_history_) + nitems - MAX_UID_RECORDS_SIZE;
+ while (overflow > 0 && io_history_.size() > 0) {
+ auto del_it = io_history_.begin();
+ overflow -= del_it->second.entries.size();
+ io_history_.erase(io_history_.begin());
+ }
}
std::map<uint64_t, struct uid_records> uid_monitor::dump(
@@ -263,7 +265,7 @@
report(nullptr);
}
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
std::map<uint64_t, struct uid_records> dump_records;
uint64_t first_ts = 0;
@@ -272,7 +274,7 @@
first_ts = time(NULL) - hours * HOUR_TO_SEC;
}
- for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) {
+ for (auto it = io_history_.lower_bound(first_ts); it != io_history_.end(); ++it) {
const std::vector<struct uid_record>& recs = it->second.entries;
struct uid_records filtered;
@@ -311,29 +313,29 @@
for (const auto& it : uid_io_stats) {
const uid_info& uid = it.second;
- if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
- curr_io_stats[uid.name] = {};
+ if (curr_io_stats_.find(uid.name) == curr_io_stats_.end()) {
+ curr_io_stats_[uid.name] = {};
}
- struct uid_io_usage& usage = curr_io_stats[uid.name];
+ struct uid_io_usage& usage = curr_io_stats_[uid.name];
usage.user_id = multiuser_get_user_id(uid.uid);
int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
- last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
+ last_uid_io_stats_[uid.uid].io[FOREGROUND].read_bytes;
int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
- last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
+ last_uid_io_stats_[uid.uid].io[BACKGROUND].read_bytes;
int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
- last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
+ last_uid_io_stats_[uid.uid].io[FOREGROUND].write_bytes;
int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
- last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
+ last_uid_io_stats_[uid.uid].io[BACKGROUND].write_bytes;
- usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] +=
+ usage.uid_ios.bytes[READ][FOREGROUND][charger_stat_] +=
(fg_rd_delta < 0) ? 0 : fg_rd_delta;
- usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] +=
+ usage.uid_ios.bytes[READ][BACKGROUND][charger_stat_] +=
(bg_rd_delta < 0) ? 0 : bg_rd_delta;
- usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] +=
+ usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat_] +=
(fg_wr_delta < 0) ? 0 : fg_wr_delta;
- usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] +=
+ usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat_] +=
(bg_wr_delta < 0) ? 0 : bg_wr_delta;
for (const auto& task_it : uid.tasks) {
@@ -341,34 +343,34 @@
const pid_t pid = task_it.first;
const std::string& comm = task_it.second.comm;
int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes -
- last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes;
+ last_uid_io_stats_[uid.uid].tasks[pid].io[FOREGROUND].read_bytes;
int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes -
- last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes;
+ last_uid_io_stats_[uid.uid].tasks[pid].io[BACKGROUND].read_bytes;
int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes -
- last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes;
+ last_uid_io_stats_[uid.uid].tasks[pid].io[FOREGROUND].write_bytes;
int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes -
- last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes;
+ last_uid_io_stats_[uid.uid].tasks[pid].io[BACKGROUND].write_bytes;
io_usage& task_usage = usage.task_ios[comm];
- task_usage.bytes[READ][FOREGROUND][charger_stat] +=
+ task_usage.bytes[READ][FOREGROUND][charger_stat_] +=
(task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta;
- task_usage.bytes[READ][BACKGROUND][charger_stat] +=
+ task_usage.bytes[READ][BACKGROUND][charger_stat_] +=
(task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta;
- task_usage.bytes[WRITE][FOREGROUND][charger_stat] +=
+ task_usage.bytes[WRITE][FOREGROUND][charger_stat_] +=
(task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta;
- task_usage.bytes[WRITE][BACKGROUND][charger_stat] +=
+ task_usage.bytes[WRITE][BACKGROUND][charger_stat_] +=
(task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta;
}
}
- last_uid_io_stats = uid_io_stats;
+ last_uid_io_stats_ = uid_io_stats;
}
void uid_monitor::report(unordered_map<int, StoragedProto>* protos)
{
if (!enabled()) return;
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
update_curr_io_stats_locked();
add_records_locked(time(NULL));
@@ -408,7 +410,7 @@
void uid_monitor::update_uid_io_proto(unordered_map<int, StoragedProto>* protos)
{
- for (const auto& item : io_history) {
+ for (const auto& item : io_history_) {
const uint64_t& end_ts = item.first;
const struct uid_records& recs = item.second;
unordered_map<userid_t, UidIOItem*> user_items;
@@ -448,9 +450,9 @@
void uid_monitor::clear_user_history(userid_t user_id)
{
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
- for (auto& item : io_history) {
+ for (auto& item : io_history_) {
vector<uid_record>* entries = &item.second.entries;
entries->erase(
remove_if(entries->begin(), entries->end(),
@@ -459,27 +461,42 @@
entries->end());
}
- for (auto it = io_history.begin(); it != io_history.end(); ) {
+ for (auto it = io_history_.begin(); it != io_history_.end(); ) {
if (it->second.entries.empty()) {
- it = io_history.erase(it);
+ it = io_history_.erase(it);
} else {
it++;
}
}
}
-void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto)
+void uid_monitor::load_uid_io_proto(userid_t user_id, const UidIOUsage& uid_io_proto)
{
if (!enabled()) return;
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
for (const auto& item_proto : uid_io_proto.uid_io_items()) {
const UidIORecords& records_proto = item_proto.records();
- struct uid_records* recs = &io_history[item_proto.end_ts()];
+ struct uid_records* recs = &io_history_[item_proto.end_ts()];
+
+ // It's possible that the same uid_io_proto file gets loaded more than
+ // once, for example, if system_server crashes. In this case we avoid
+ // adding duplicate entries, so we build a quick way to check for
+ // duplicates.
+ std::unordered_set<std::string> existing_uids;
+ for (const auto& rec : recs->entries) {
+ if (rec.ios.user_id == user_id) {
+ existing_uids.emplace(rec.name);
+ }
+ }
recs->start_ts = records_proto.start_ts();
for (const auto& rec_proto : records_proto.entries()) {
+ if (existing_uids.find(rec_proto.uid_name()) != existing_uids.end()) {
+ continue;
+ }
+
struct uid_record record;
record.name = rec_proto.uid_name();
record.ios.user_id = rec_proto.user_id();
@@ -492,29 +509,35 @@
}
recs->entries.push_back(record);
}
+
+ // We already added items, so this will just cull down to the maximum
+ // length. We do not remove anything if there is only one entry.
+ if (io_history_.size() > 1) {
+ maybe_shrink_history_for_items(0);
+ }
}
}
void uid_monitor::set_charger_state(charger_stat_t stat)
{
- Mutex::Autolock _l(uidm_mutex);
+ Mutex::Autolock _l(uidm_mutex_);
- if (charger_stat == stat) {
+ if (charger_stat_ == stat) {
return;
}
update_curr_io_stats_locked();
- charger_stat = stat;
+ charger_stat_ = stat;
}
void uid_monitor::init(charger_stat_t stat)
{
- charger_stat = stat;
+ charger_stat_ = stat;
- start_ts = time(NULL);
- last_uid_io_stats = get_uid_io_stats();
+ start_ts_ = time(NULL);
+ last_uid_io_stats_ = get_uid_io_stats();
}
uid_monitor::uid_monitor()
- : enable(!access(UID_IO_STATS_PATH, R_OK)) {
+ : enabled_(!access(UID_IO_STATS_PATH, R_OK)) {
}
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index ec47b65..64009c2 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -443,8 +443,9 @@
TEST(storaged_test, uid_monitor) {
uid_monitor uidm;
+ auto& io_history = uidm.io_history();
- uidm.io_history[200] = {
+ io_history[200] = {
.start_ts = 100,
.entries = {
{ "app1", {
@@ -466,7 +467,7 @@
},
};
- uidm.io_history[300] = {
+ io_history[300] = {
.start_ts = 200,
.entries = {
{ "app1", {
@@ -526,9 +527,9 @@
EXPECT_EQ(user_1_item_1.records().entries(0).user_id(), 1UL);
EXPECT_EQ(user_1_item_1.records().entries(0).uid_io().wr_fg_chg_off(), 1000UL);
- uidm.io_history.clear();
+ io_history.clear();
- uidm.io_history[300] = {
+ io_history[300] = {
.start_ts = 200,
.entries = {
{ "app1", {
@@ -539,7 +540,7 @@
},
};
- uidm.io_history[400] = {
+ io_history[400] = {
.start_ts = 300,
.entries = {
{ "app1", {
@@ -550,16 +551,16 @@
},
};
- uidm.load_uid_io_proto(protos[0].uid_io_usage());
- uidm.load_uid_io_proto(protos[1].uid_io_usage());
+ uidm.load_uid_io_proto(0, protos[0].uid_io_usage());
+ uidm.load_uid_io_proto(1, protos[1].uid_io_usage());
- EXPECT_EQ(uidm.io_history.size(), 3UL);
- EXPECT_EQ(uidm.io_history.count(200), 1UL);
- EXPECT_EQ(uidm.io_history.count(300), 1UL);
- EXPECT_EQ(uidm.io_history.count(400), 1UL);
+ EXPECT_EQ(io_history.size(), 3UL);
+ EXPECT_EQ(io_history.count(200), 1UL);
+ EXPECT_EQ(io_history.count(300), 1UL);
+ EXPECT_EQ(io_history.count(400), 1UL);
- EXPECT_EQ(uidm.io_history[200].start_ts, 100UL);
- const vector<struct uid_record>& entries_0 = uidm.io_history[200].entries;
+ EXPECT_EQ(io_history[200].start_ts, 100UL);
+ const vector<struct uid_record>& entries_0 = io_history[200].entries;
EXPECT_EQ(entries_0.size(), 3UL);
EXPECT_EQ(entries_0[0].name, "app1");
EXPECT_EQ(entries_0[0].ios.user_id, 0UL);
@@ -572,8 +573,8 @@
EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL);
EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_ON], 1000UL);
- EXPECT_EQ(uidm.io_history[300].start_ts, 200UL);
- const vector<struct uid_record>& entries_1 = uidm.io_history[300].entries;
+ EXPECT_EQ(io_history[300].start_ts, 200UL);
+ const vector<struct uid_record>& entries_1 = io_history[300].entries;
EXPECT_EQ(entries_1.size(), 3UL);
EXPECT_EQ(entries_1[0].name, "app1");
EXPECT_EQ(entries_1[0].ios.user_id, 0UL);
@@ -585,8 +586,8 @@
EXPECT_EQ(entries_1[2].ios.user_id, 1UL);
EXPECT_EQ(entries_1[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL);
- EXPECT_EQ(uidm.io_history[400].start_ts, 300UL);
- const vector<struct uid_record>& entries_2 = uidm.io_history[400].entries;
+ EXPECT_EQ(io_history[400].start_ts, 300UL);
+ const vector<struct uid_record>& entries_2 = io_history[400].entries;
EXPECT_EQ(entries_2.size(), 1UL);
EXPECT_EQ(entries_2[0].name, "app1");
EXPECT_EQ(entries_2[0].ios.user_id, 0UL);
@@ -615,14 +616,71 @@
uidm.clear_user_history(0);
- EXPECT_EQ(uidm.io_history.size(), 2UL);
- EXPECT_EQ(uidm.io_history.count(200), 1UL);
- EXPECT_EQ(uidm.io_history.count(300), 1UL);
+ EXPECT_EQ(io_history.size(), 2UL);
+ EXPECT_EQ(io_history.count(200), 1UL);
+ EXPECT_EQ(io_history.count(300), 1UL);
- EXPECT_EQ(uidm.io_history[200].entries.size(), 1UL);
- EXPECT_EQ(uidm.io_history[300].entries.size(), 1UL);
+ EXPECT_EQ(io_history[200].entries.size(), 1UL);
+ EXPECT_EQ(io_history[300].entries.size(), 1UL);
uidm.clear_user_history(1);
- EXPECT_EQ(uidm.io_history.size(), 0UL);
+ EXPECT_EQ(io_history.size(), 0UL);
+}
+
+TEST(storaged_test, load_uid_io_proto) {
+ uid_monitor uidm;
+ auto& io_history = uidm.io_history();
+
+ static const uint64_t kProtoTime = 200;
+ io_history[kProtoTime] = {
+ .start_ts = 100,
+ .entries = {
+ { "app1", {
+ .user_id = 0,
+ .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000,
+ }
+ },
+ { "app2", {
+ .user_id = 0,
+ .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 2000,
+ }
+ },
+ { "app3", {
+ .user_id = 0,
+ .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 3000,
+ }
+ },
+ },
+ };
+
+ unordered_map<int, StoragedProto> protos;
+ uidm.update_uid_io_proto(&protos);
+ ASSERT_EQ(protos.size(), size_t(1));
+
+ // Loading the same proto many times should not add duplicate entries.
+ UidIOUsage user_0 = protos[0].uid_io_usage();
+ for (size_t i = 0; i < 10000; i++) {
+ uidm.load_uid_io_proto(0, user_0);
+ }
+ ASSERT_EQ(io_history.size(), size_t(1));
+ ASSERT_EQ(io_history[kProtoTime].entries.size(), size_t(3));
+
+ // Create duplicate entries until we go over the limit.
+ auto record = io_history[kProtoTime];
+ io_history.clear();
+ for (size_t i = 0; i < uid_monitor::MAX_UID_RECORDS_SIZE * 2; i++) {
+ if (i == kProtoTime) {
+ continue;
+ }
+ io_history[i] = record;
+ }
+ ASSERT_GT(io_history.size(), size_t(uid_monitor::MAX_UID_RECORDS_SIZE));
+
+ // After loading, the history should be truncated.
+ for (auto& item : *user_0.mutable_uid_io_items()) {
+ item.set_end_ts(io_history.size());
+ }
+ uidm.load_uid_io_proto(0, user_0);
+ ASSERT_LE(io_history.size(), size_t(uid_monitor::MAX_UID_RECORDS_SIZE));
}