Merge "bootstat: Migrate to StatsLog for metrics"
diff --git a/adb/Android.bp b/adb/Android.bp
index 7e3be61..5073568 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -160,7 +160,11 @@
// libadbconnection_client doesn't need an embedded build number.
use_version_lib: false,
- version_script: "adbconnection/libadbconnection_client.map.txt",
+ target: {
+ linux: {
+ version_script: "adbconnection/libadbconnection_client.map.txt",
+ },
+ },
stubs: {
symbol_file: "adbconnection/libadbconnection_client.map.txt",
versions: ["1"],
@@ -320,6 +324,7 @@
cc_binary_host {
name: "adb",
+ stl: "libc++_static",
defaults: ["adb_defaults"],
srcs: [
@@ -360,8 +365,6 @@
"libz",
],
- stl: "libc++_static",
-
// Don't add anything here, we don't want additional shared dependencies
// on the host adb tool, and shared libraries that link against libc++
// will violate ODR
@@ -539,6 +542,7 @@
cc_binary {
name: "adbd",
defaults: ["adbd_defaults", "host_adbd_supported"],
+ stl: "libc++_static",
recovery_available: true,
srcs: [
@@ -554,11 +558,9 @@
keep_symbols: true,
},
- stl: "libc++_static",
static_libs: [
"libadbconnection_server",
"libadbd",
- "libadbd_auth",
"libadbd_services",
"libasyncio",
"libbase",
@@ -573,15 +575,17 @@
],
shared_libs: [
+ "libadbd_auth",
"libcrypto",
],
+
+ required: ["libadbd_auth"],
}
phony {
name: "adbd_system_binaries",
required: [
"abb",
- "libadbd_auth",
"reboot",
"set-verity-state",
]
@@ -598,6 +602,7 @@
name: "abb",
defaults: ["adbd_defaults"],
+ stl: "libc++",
recovery_available: false,
srcs: [
@@ -630,7 +635,11 @@
cc_test {
name: "adbd_test",
+
defaults: ["adbd_defaults"],
+ stl: "libc++_static",
+
+ recovery_available: false,
srcs: libadb_test_srcs + [
"daemon/services.cpp",
"daemon/shell_service.cpp",
@@ -652,7 +661,7 @@
"libmdnssd",
"libselinux",
],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "mts"],
require_root: true,
}
@@ -735,7 +744,6 @@
"libziparchive",
"libz",
],
- stl: "libc++_static",
proto: {
type: "lite",
export_proto_headers: true,
diff --git a/adb/apex/ld.config.txt b/adb/apex/ld.config.txt
index d1858a4..ca297fe 100644
--- a/adb/apex/ld.config.txt
+++ b/adb/apex/ld.config.txt
@@ -5,16 +5,24 @@
dir.adbd = /apex/com.android.adbd/bin/
[adbd]
-additional.namespaces = platform,art
+additional.namespaces = apex,platform,art
namespace.default.isolated = true
-namespace.default.search.paths = /apex/com.android.adbd/${LIB}
-namespace.default.asan.search.paths = /apex/com.android.adbd/${LIB}
namespace.default.permitted.paths = /system/${LIB}
namespace.default.asan.permitted.paths = /system/${LIB}
-namespace.default.links = art,platform
+namespace.default.links = apex,art,platform
+namespace.default.link.apex.shared_libs = libcrypto.so
namespace.default.link.art.shared_libs = libadbconnection_server.so
-namespace.default.link.platform.shared_libs = libc.so:libdl.so:libm.so:libclang_rt.hwasan-aarch64-android.so
+
+# libcrypto.so in the APEX might be a symlink to /system, for APEXes bundled with the system image.
+# The dynamic linker works off of realpath, so we need to permit loading libcrypto.so from /system.
+namespace.default.link.platform.shared_libs = libc.so:libdl.so:libm.so:libclang_rt.hwasan-aarch64-android.so:liblog.so:libadbd_auth.so:libcrypto.so
+
+namespace.apex.isolated = true
+namespace.apex.search.paths = /apex/com.android.adbd/${LIB}
+namespace.apex.asan.search.paths = /apex/com.android.adbd/${LIB}
+namespace.apex.links = platform
+namespace.apex.link.platform.allow_all_shared_libs = true
###############################################################################
# "art" APEX namespace: used for libadbdconnection_server
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 73dcde1..2bcd0a6 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -227,16 +227,20 @@
return 1;
}
- copy_to_file(local_fd.get(), remote_fd.get());
+ if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+ fprintf(stderr, "adb: failed to install: copy_to_file: %s: %s", file, strerror(errno));
+ return 1;
+ }
char buf[BUFSIZ];
read_status_line(remote_fd.get(), buf, sizeof(buf));
- if (!strncmp("Success", buf, 7)) {
- fputs(buf, stdout);
- return 0;
+ if (strncmp("Success", buf, 7) != 0) {
+ fprintf(stderr, "adb: failed to install %s: %s", file, buf);
+ return 1;
}
- fprintf(stderr, "adb: failed to install %s: %s", file, buf);
- return 1;
+
+ fputs(buf, stdout);
+ return 0;
}
static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) {
@@ -455,7 +459,12 @@
goto finalize_session;
}
- copy_to_file(local_fd.get(), remote_fd.get());
+ if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+ fprintf(stderr, "adb: failed to write \"%s\": %s\n", file, strerror(errno));
+ success = false;
+ goto finalize_session;
+ }
+
read_status_line(remote_fd.get(), buf, sizeof(buf));
if (strncmp("Success", buf, 7)) {
@@ -634,7 +643,11 @@
goto finalize_multi_package_session;
}
- copy_to_file(local_fd.get(), remote_fd.get());
+ if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+ fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno));
+ goto finalize_multi_package_session;
+ }
+
read_status_line(remote_fd.get(), buf, sizeof(buf));
if (strncmp("Success", buf, 7)) {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index a6d7e31..c302965 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -352,7 +352,8 @@
#endif
}
-void copy_to_file(int inFd, int outFd) {
+bool copy_to_file(int inFd, int outFd) {
+ bool result = true;
std::vector<char> buf(64 * 1024);
int len;
long total = 0;
@@ -375,6 +376,7 @@
}
if (len < 0) {
D("copy_to_file(): read failed: %s", strerror(errno));
+ result = false;
break;
}
if (outFd == STDOUT_FILENO) {
@@ -388,7 +390,8 @@
stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
- D("copy_to_file() finished after %lu bytes", total);
+ D("copy_to_file() finished with %s after %lu bytes", result ? "success" : "failure", total);
+ return result;
}
static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
index ab77b29..b9dee56 100644
--- a/adb/client/commandline.h
+++ b/adb/client/commandline.h
@@ -100,7 +100,7 @@
int adb_commandline(int argc, const char** argv);
-void copy_to_file(int inFd, int outFd);
+bool copy_to_file(int inFd, int outFd);
// Connects to the device "shell" service with |command| and prints the
// resulting output.
diff --git a/base/expected_test.cpp b/base/expected_test.cpp
index a74bc1d..6c3d421 100644
--- a/base/expected_test.cpp
+++ b/base/expected_test.cpp
@@ -499,24 +499,6 @@
EXPECT_TRUE(e4 != e3);
}
-TEST(Expected, testCompareWithSameValue) {
- exp_int e = 10;
- int value = 10;
- EXPECT_TRUE(e == value);
- EXPECT_TRUE(value == e);
- EXPECT_FALSE(e != value);
- EXPECT_FALSE(value != e);
-}
-
-TEST(Expected, testCompareWithDifferentValue) {
- exp_int e = 10;
- int value = 20;
- EXPECT_FALSE(e == value);
- EXPECT_FALSE(value == e);
- EXPECT_TRUE(e != value);
- EXPECT_TRUE(value != e);
-}
-
TEST(Expected, testCompareWithSameError) {
exp_int e = unexpected(10);
exp_int::unexpected_type error = 10;
@@ -594,7 +576,7 @@
EXPECT_EQ(-1, divide(10, 0).error().cause);
EXPECT_TRUE(divide(10, 3));
- EXPECT_EQ(QR(3, 1), divide(10, 3));
+ EXPECT_EQ(QR(3, 1), *divide(10, 3));
}
TEST(Expected, testPair) {
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index b3f5adb..44e0b4a 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -366,16 +366,6 @@
template<class T1, class E1, class T2, class E2>
friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
- // comparison with T
- template<class T1, class E1, class T2>
- friend constexpr bool operator==(const expected<T1, E1>&, const T2&);
- template<class T1, class E1, class T2>
- friend constexpr bool operator==(const T2&, const expected<T1, E1>&);
- template<class T1, class E1, class T2>
- friend constexpr bool operator!=(const expected<T1, E1>&, const T2&);
- template<class T1, class E1, class T2>
- friend constexpr bool operator!=(const T2&, const expected<T1, E1>&);
-
// Comparison with unexpected<E>
template<class T1, class E1, class E2>
friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
@@ -410,24 +400,6 @@
return !(x == y);
}
-// comparison with T
-template<class T1, class E1, class T2>
-constexpr bool operator==(const expected<T1, E1>& x, const T2& y) {
- return x.has_value() && (*x == y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator==(const T2& x, const expected<T1, E1>& y) {
- return y.has_value() && (x == *y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const expected<T1, E1>& x, const T2& y) {
- return !x.has_value() || (*x != y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const T2& x, const expected<T1, E1>& y) {
- return !y.has_value() || (x != *y);
-}
-
// Comparison with unexpected<E>
template<class T1, class E1, class E2>
constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index f379d76..2f2919f 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -7,7 +7,7 @@
# - watch adb logcat -b all -d -s bootstat
# - watch adb logcat -b all -d | audit2allow
# - wait until screen is up, boot has completed, can mean wait for
-# sys.boot_completed=1 and sys.logbootcomplete=1 to be true
+# sys.boot_completed=1 and sys.bootstat.first_boot_completed=1 to be true
#
# All test frames, and nothing else, must be function names prefixed and
# specifiged with the pattern 'test_<test>() {' as this is also how the
@@ -230,16 +230,16 @@
if [ -n "`get_property sys.boot.reason`" ]
then
vals=`get_property |
- sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
- if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
- then
- sleep 1
- break
- fi
- if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
- then
- sleep 1
- break
+ sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\|bootstat[.]first_boot_completed\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+ if [ X"${vals}" != X"${vals##*boot_completed=1}" ]; then
+ if [ X"${vals}" != X"${vals##*logbootcomple=1}" ]; then
+ sleep 1
+ break
+ fi
+ if [ X"${vals}" != X"${vals##*bootstat.first_boot_completed=1}" ]; then
+ sleep 1
+ break
+ fi
fi
fi
fi
@@ -384,15 +384,15 @@
init : processing action (boot) from (/system/etc/init/bootstat.rc
init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
init : processing action (ro.boot.bootreason=* && post-fs) from (/system/etc/init/bootstat.rc
-init : processing action (zygote-start) from (/system/etc/init/bootstat.rc
-init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
+init : processing action (sys.bootstat.first_zygote_start=0 && zygote-start) from (/system/etc/init/bootstat.rc
+init : processing action (sys.boot_completed=1 && sys.bootstat.first_boot_completed=0) from (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
(/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
(/system/bin/bootstat -r post_decrypt_time_elapsed)'
-init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc
+init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete)'...
(/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
(/system/bin/bootstat --record_boot_reason)'...
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 85caf25..a350fe7 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -50,34 +50,34 @@
on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
exec_background - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed
-# sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
-# This signaling is necessary to prevent logging boot metrics after a runtime
-# restart (e.g., adb shell stop && adb shell start). /proc/uptime is not reset
-# during a runtime restart, which leads to false boot time metrics being reported.
+# Initialize bootstat state machine.
#
-# The 'on boot' event occurs once per hard boot (device power on), which
-# switches the flag on. If the device performs a runtime restart, the flag is
-# switched off and cannot be switched on until the device hard boots again.
-
-# Enable bootstat logging on boot.
-on boot
- setprop sys.logbootcomplete 1
-
-# Disable further bootstat logging on a runtime restart. A runtime restart is
-# signaled by the zygote stopping.
-on property:init.svc.zygote=stopping
- setprop sys.logbootcomplete 0
+# sys.bootstat.first_boot_completed: responsible for making sure that record_boot_complete happens
+# only once per device hard reboot. Possible values:
+#
+# sys.bootstat.first_boot_completed=0 - first boot completed trigger wasn't processed yet.
+# sys.bootstat.first_boot_completed=1 - first boot completed trigger was processed and
+# record_boot_complete was called. Subsequent boot completed
+# triggers (e.g. due to userspace reboot) won't retrigger
+# record_boot_complete
+#
+# IMPORTANT, ro.persistent_properties.ready=1 trigger is used here to ensure that we initialize
+# state machine only once, which as result ensures that bootstat --set_system_boot_reason and
+# bootstat --record_boot_complete will be called only once per full reboot.
+on property:ro.persistent_properties.ready=true
+ setprop sys.bootstat.first_boot_completed 0
# Set boot reason
-on zygote-start
+on property:ro.persistent_properties.ready=true
# Converts bootloader boot reason and persist.sys.boot.reason to system boot reason
# Need go after persist peroperties are loaded which is right before zygote-start trigger
exec_background - system log -- /system/bin/bootstat --set_system_boot_reason
# Record boot complete metrics.
-on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
+on property:sys.boot_completed=1 && property:sys.bootstat.first_boot_completed=0
# Record boot_complete and related stats (decryption, etc).
# Record the boot reason.
# Record time since factory reset.
# Log all boot events.
exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
+ setprop sys.bootstat.first_boot_completed 1
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7a88aa3..f5daf91 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -96,6 +96,10 @@
export_header_lib_headers: [
"libfiemap_headers",
],
+ required: [
+ "e2freefrag",
+ "e2fsdroid",
+ ],
}
// Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
new file mode 100644
index 0000000..de38ff6
--- /dev/null
+++ b/fs_mgr/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "libdm_test"
+ },
+ {
+ "name": "liblp_test"
+ }
+ ]
+}
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index acf4d7b..a8c2cc1 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -24,6 +24,7 @@
#include <cutils/partition_utils.h>
#include <sys/mount.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4.h>
#include <ext4_utils/ext4_utils.h>
@@ -57,7 +58,7 @@
}
static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_point,
- bool crypt_footer) {
+ bool crypt_footer, bool needs_projid) {
uint64_t dev_sz;
int rc = 0;
@@ -72,11 +73,20 @@
}
std::string size_str = std::to_string(dev_sz / 4096);
- const char* const mke2fs_args[] = {
- "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev.c_str(),
- size_str.c_str(), nullptr};
- rc = logwrap_fork_execvp(arraysize(mke2fs_args), mke2fs_args, nullptr, false, LOG_KLOG, true,
+ std::vector<const char*> mke2fs_args = {"/system/bin/mke2fs", "-t", "ext4", "-b", "4096"};
+
+ // Project ID's require wider inodes. The Quotas themselves are enabled by tune2fs during boot.
+ if (needs_projid) {
+ mke2fs_args.push_back("-I");
+ mke2fs_args.push_back("512");
+ }
+ // casefolding is enabled via tune2fs during boot.
+
+ mke2fs_args.push_back(fs_blkdev.c_str());
+ mke2fs_args.push_back(size_str.c_str());
+
+ rc = logwrap_fork_execvp(mke2fs_args.size(), mke2fs_args.data(), nullptr, false, LOG_KLOG, true,
nullptr);
if (rc) {
LERROR << "mke2fs returned " << rc;
@@ -95,7 +105,8 @@
return rc;
}
-static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool crypt_footer) {
+static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool crypt_footer,
+ bool needs_projid, bool needs_casefold) {
if (!dev_sz) {
int rc = get_dev_sz(fs_blkdev, &dev_sz);
if (rc) {
@@ -109,26 +120,40 @@
}
std::string size_str = std::to_string(dev_sz / 4096);
- // clang-format off
- const char* const args[] = {
- "/system/bin/make_f2fs",
- "-g", "android",
- fs_blkdev.c_str(),
- size_str.c_str(),
- nullptr
- };
- // clang-format on
- return logwrap_fork_execvp(arraysize(args), args, nullptr, false, LOG_KLOG, true, nullptr);
+ std::vector<const char*> args = {"/system/bin/make_f2fs", "-g", "android"};
+ if (needs_projid) {
+ args.push_back("-O");
+ args.push_back("project_quota,extra_attr");
+ }
+ if (needs_casefold) {
+ args.push_back("-O");
+ args.push_back("casefold");
+ args.push_back("-C");
+ args.push_back("utf8");
+ }
+ args.push_back(fs_blkdev.c_str());
+ args.push_back(size_str.c_str());
+
+ return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, true, nullptr);
}
int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
LERROR << __FUNCTION__ << ": Format " << entry.blk_device << " as '" << entry.fs_type << "'";
+ bool needs_casefold = false;
+ bool needs_projid = false;
+
+ if (entry.mount_point == "/data") {
+ needs_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
+ needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false);
+ }
+
if (entry.fs_type == "f2fs") {
- return format_f2fs(entry.blk_device, entry.length, crypt_footer);
+ return format_f2fs(entry.blk_device, entry.length, crypt_footer, needs_projid,
+ needs_casefold);
} else if (entry.fs_type == "ext4") {
- return format_ext4(entry.blk_device, entry.mount_point, crypt_footer);
+ return format_ext4(entry.blk_device, entry.mount_point, crypt_footer, needs_projid);
} else {
LERROR << "File system type '" << entry.fs_type << "' is not supported";
return -EINVAL;
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 8a924d5..1c3427f 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -54,29 +54,32 @@
}
cc_defaults {
- name: "libdm_defaults",
+ name: "libdm_test_defaults",
defaults: ["fs_mgr_defaults"],
static_libs: [
"libdm",
+ ],
+ shared_libs: [
"libbase",
"libext2_uuid",
"libfs_mgr",
"liblog",
],
srcs: [":libdm_test_srcs"],
+ auto_gen_config: true,
+ require_root: true,
}
cc_test {
name: "libdm_test",
- defaults: ["libdm_defaults"],
+ defaults: ["libdm_test_defaults"],
+ test_suites: ["device-tests"],
}
cc_test {
name: "vts_libdm_test",
- defaults: ["libdm_defaults"],
+ defaults: ["libdm_test_defaults"],
test_suites: ["vts-core"],
- auto_gen_config: true,
- require_root: true,
test_min_api_level: 29,
}
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index b296801..affdd29 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -533,7 +533,9 @@
if (is_legacy) {
ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
} else {
- ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 0 /dev/loop0 0");
+ ASSERT_EQ(target.GetParameterString(),
+ "AES-256-XTS abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
+ "iv_large_sectors");
}
}
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 0195716..6717922 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -252,7 +252,7 @@
// For dm-linear devices sitting on top of /data, we cannot risk deleting
// the file. The underlying blocks could be reallocated by the filesystem.
if (IsImageMapped(name)) {
- LOG(ERROR) << "Backing image " << name << " is currently mapped to a block device";
+ LOG(ERROR) << "Cannot delete backing image " << name << " because mapped to a block device";
return false;
}
diff --git a/fs_mgr/libfiemap/metadata.cpp b/fs_mgr/libfiemap/metadata.cpp
index ea1f508..b0dfb5c 100644
--- a/fs_mgr/libfiemap/metadata.cpp
+++ b/fs_mgr/libfiemap/metadata.cpp
@@ -39,7 +39,13 @@
bool MetadataExists(const std::string& metadata_dir) {
auto metadata_file = GetMetadataFile(metadata_dir);
- return access(metadata_file.c_str(), F_OK) == 0;
+ if (access(metadata_file.c_str(), F_OK)) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Access " << metadata_file << " failed:";
+ }
+ return false;
+ }
+ return true;
}
std::unique_ptr<LpMetadata> OpenMetadata(const std::string& metadata_dir) {
@@ -61,7 +67,7 @@
std::unique_ptr<MetadataBuilder> builder;
if (access(metadata_file.c_str(), R_OK)) {
if (errno != ENOENT) {
- PLOG(ERROR) << "access " << metadata_file << " failed:";
+ PLOG(ERROR) << "Access " << metadata_file << " failed:";
return nullptr;
}
@@ -112,7 +118,12 @@
bool RemoveAllMetadata(const std::string& dir) {
auto metadata_file = GetMetadataFile(dir);
- return android::base::RemoveFileIfExists(metadata_file);
+ std::string err;
+ if (!android::base::RemoveFileIfExists(metadata_file, &err)) {
+ LOG(ERROR) << "Could not remove metadata file: " << err;
+ return false;
+ }
+ return true;
}
bool FillPartitionExtents(MetadataBuilder* builder, Partition* partition, SplitFiemap* file,
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 8770a6b..50de42c 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -266,8 +266,10 @@
return avb_handle;
}
-AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
- if (fstab_entry.avb_keys.empty()) {
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+ const std::vector<std::string>& preload_avb_key_blobs) {
+ // At least one of the following should be provided for public key matching.
+ if (preload_avb_key_blobs.empty() && fstab_entry.avb_keys.empty()) {
LERROR << "avb_keys=/path/to/key(s) is missing for " << fstab_entry.mount_point;
return nullptr;
}
@@ -309,18 +311,36 @@
return nullptr;
}
- // fstab_entry.avb_keys might be either a directory containing multiple keys,
- // or a string indicating multiple keys separated by ':'.
- std::vector<std::string> allowed_avb_keys;
- auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
- if (list_avb_keys_in_dir) {
- std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
- allowed_avb_keys = *list_avb_keys_in_dir;
- } else {
- allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+ bool public_key_match = false;
+ // Performs key matching for preload_avb_key_blobs first, if it is present.
+ if (!public_key_data.empty() && !preload_avb_key_blobs.empty()) {
+ if (std::find(preload_avb_key_blobs.begin(), preload_avb_key_blobs.end(),
+ public_key_data) != preload_avb_key_blobs.end()) {
+ public_key_match = true;
+ }
+ }
+ // Performs key matching for fstab_entry.avb_keys if necessary.
+ // Note that it is intentional to match both preload_avb_key_blobs and fstab_entry.avb_keys.
+ // Some keys might only be availble before init chroots into /system, e.g., /avb/key1
+ // in the first-stage ramdisk, while other keys might only be available after the chroot,
+ // e.g., /system/etc/avb/key2.
+ if (!public_key_data.empty() && !public_key_match) {
+ // fstab_entry.avb_keys might be either a directory containing multiple keys,
+ // or a string indicating multiple keys separated by ':'.
+ std::vector<std::string> allowed_avb_keys;
+ auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
+ if (list_avb_keys_in_dir) {
+ std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
+ allowed_avb_keys = *list_avb_keys_in_dir;
+ } else {
+ allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+ }
+ if (ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+ public_key_match = true;
+ }
}
- if (!ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+ if (!public_key_match) {
avb_handle->status_ = AvbHandleStatus::kVerificationError;
LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point;
if (!allow_verification_error) {
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 521f2d5..4702e68 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -85,8 +85,15 @@
// TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
static AvbUniquePtr Open(); // loads inline vbmeta, via libavb.
static AvbUniquePtr LoadAndVerifyVbmeta(); // loads inline vbmeta.
- static AvbUniquePtr LoadAndVerifyVbmeta(
- const FstabEntry& fstab_entry); // loads offline vbmeta.
+
+ // The caller can specify optional preload_avb_key_blobs for public key matching.
+ // This is mostly for init to preload AVB keys before chroot into /system.
+ // Both preload_avb_key_blobs and fstab_entry.avb_keys (file paths) will be used
+ // for public key matching.
+ static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
+ const FstabEntry& fstab_entry,
+ const std::vector<std::string>& preload_avb_key_blobs = {});
+
static AvbUniquePtr LoadAndVerifyVbmeta( // loads offline vbmeta.
const std::string& partition_name, const std::string& ab_suffix,
const std::string& ab_other_suffix, const std::string& expected_public_key,
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ad48b82..c58101a 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -95,6 +95,16 @@
static_libs: [
"libfs_mgr_binder"
],
+
+ shared_libs: [
+ // TODO(b/148818798): remove when parent bug is fixed
+ "libutilscallstack",
+ ],
+ cflags: [
+ "-g",
+ "-O0",
+ "-DLIBSNAPSHOT_USE_CALLSTACK",
+ ],
}
cc_library_static {
@@ -171,6 +181,9 @@
"libsparse",
"libutils",
"libz",
+
+ // TODO(b/148818798): remove when parent bug is fixed
+ "libutilscallstack",
],
static_libs: [
"libgmock",
@@ -207,6 +220,9 @@
"liblp",
"libprotobuf-cpp-lite",
"libutils",
+
+ // TODO(b/148818798): remove when parent bug is fixed.
+ "libutilscallstack",
],
init_rc: [
"snapshotctl.rc",
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 785882a..63a9302 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,6 +21,7 @@
#include <sys/unistd.h>
#include <optional>
+#include <sstream>
#include <thread>
#include <unordered_set>
@@ -37,6 +38,10 @@
#include <libfiemap/image_manager.h>
#include <liblp/liblp.h>
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+#include <utils/CallStack.h>
+#endif
+
#include <android/snapshot/snapshot.pb.h>
#include "device_info.h"
#include "partition_cow_creator.h"
@@ -197,6 +202,22 @@
}
bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
+ LOG(INFO) << "Removing all update state.";
+
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+ LOG(WARNING) << "Logging stack; see b/148818798.";
+ // Do not use CallStack's log functions because snapshotctl relies on
+ // android-base/logging to save log to files.
+ // TODO(b/148818798): remove this before we ship.
+ CallStack callstack;
+ callstack.update();
+ auto callstack_str = callstack.toString();
+ LOG(WARNING) << callstack_str.c_str();
+ std::stringstream path;
+ path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
+ android::base::WriteStringToFile(callstack_str.c_str(), path.str());
+#endif
+
if (!RemoveAllSnapshots(lock)) {
LOG(ERROR) << "Could not remove all snapshots";
return false;
@@ -1709,6 +1730,8 @@
return UpdateState::MergeNeedsReboot;
} else if (contents == "merge-failed") {
return UpdateState::MergeFailed;
+ } else if (contents == "cancelled") {
+ return UpdateState::Cancelled;
} else {
LOG(ERROR) << "Unknown merge state in update state file: \"" << contents << "\"";
return UpdateState::None;
@@ -1731,6 +1754,8 @@
return os << "merge-needs-reboot";
case UpdateState::MergeFailed:
return os << "merge-failed";
+ case UpdateState::Cancelled:
+ return os << "cancelled";
default:
LOG(ERROR) << "Unknown update state: " << static_cast<uint32_t>(state);
return os;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c49c49e..c5ad44c 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -335,6 +335,7 @@
return AssertionSuccess();
}
+ static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
bool is_virtual_ab_;
DeviceMapper& dm_;
std::unique_ptr<SnapshotManager::LockedFile> lock_;
@@ -511,7 +512,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
ASSERT_TRUE(AcquireLock());
@@ -540,7 +541,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
ASSERT_TRUE(AcquireLock());
@@ -567,7 +568,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
ASSERT_TRUE(init->InitiateMerge());
// Now, reflash super. Note that we haven't called ProcessUpdateState, so the
@@ -577,7 +578,7 @@
FormatFakeSuper();
ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Because the status is Merging, we must call ProcessUpdateState, which should
// detect a cancelled update.
@@ -1012,7 +1013,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Check that the target partitions have the same content.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1140,7 +1141,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Check that the target partitions have the same content.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1152,7 +1153,7 @@
init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_a"));
ASSERT_NE(init, nullptr);
ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Assert that the source partitions aren't affected.
for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -1189,7 +1190,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
init = nullptr;
// Initiate the merge and wait for it to be completed.
@@ -1325,7 +1326,7 @@
// won't be set.
auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Keep an open handle to the cow device. This should cause the merge to
// be incomplete.
@@ -1341,7 +1342,7 @@
ASSERT_TRUE(UnmapAll());
// init does first stage mount again.
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// sys_b should be mapped as a dm-linear device directly.
ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
@@ -1427,7 +1428,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
init = nullptr;
// Initiate the merge and then immediately stop it to simulate a reboot.
@@ -1532,7 +1533,7 @@
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Check that the target partition have the same content. Hashtree and FEC extents
// should be accounted for.
@@ -1584,7 +1585,7 @@
{
auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
ASSERT_NE(nullptr, init);
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
}
auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
@@ -1630,7 +1631,7 @@
public:
AssertionResult InitiateMerge(const std::string& slot_suffix) {
auto sm = SnapshotManager::New(new TestDeviceInfo(fake_super, slot_suffix));
- if (!sm->CreateLogicalAndSnapshotPartitions("super")) {
+ if (!sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)) {
return AssertionFailure() << "Cannot CreateLogicalAndSnapshotPartitions";
}
if (!sm->InitiateMerge()) {
@@ -1712,7 +1713,7 @@
if (flashed_slot && after_merge) {
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
}
- ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
// Check that the target partitions have the same content.
for (const auto& name : {"sys", "vnd"}) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 1bc0357..9f23c45 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -19,9 +19,15 @@
#include <chrono>
#include <iostream>
#include <map>
+#include <sstream>
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include <libsnapshot/snapshot.h>
+#include "utility.h"
+
+#include "utility.h"
using namespace std::string_literals;
@@ -31,9 +37,11 @@
"Actions:\n"
" dump\n"
" Print snapshot states.\n"
- " merge [--logcat]\n"
+ " merge [--logcat] [--log-to-file]\n"
" Initialize merge and wait for it to be completed.\n"
- " If --logcat is specified, log to logcat. Otherwise, log to stdout.\n";
+ " If --logcat is specified, log to logcat.\n"
+ " If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
+ " If both specified, log to both. If none specified, log to stdout.\n";
return EX_USAGE;
}
@@ -45,20 +53,62 @@
return SnapshotManager::New()->Dump(std::cout);
}
+class FileLogger {
+ public:
+ FileLogger() {
+ static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
+ std::stringstream ss;
+ ss << kLogFilePath << "snapshotctl." << Now() << ".log";
+ fd_.reset(TEMP_FAILURE_RETRY(
+ open(ss.str().c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)));
+ }
+ // Copy-contuctor needed to be converted to std::function.
+ FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
+ void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
+ const char* /*file*/, unsigned int /*line*/, const char* message) {
+ if (fd_ == -1) return;
+ std::stringstream ss;
+ ss << Now() << ":" << message << "\n";
+ (void)android::base::WriteStringToFd(ss.str(), fd_);
+ }
+
+ private:
+ android::base::unique_fd fd_;
+};
+
+class MergeCmdLogger {
+ public:
+ MergeCmdLogger(int argc, char** argv) {
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i] == "--logcat"s) {
+ loggers_.push_back(android::base::LogdLogger());
+ }
+ if (argv[i] == "--log-to-file"s) {
+ loggers_.push_back(std::move(FileLogger()));
+ }
+ }
+ if (loggers_.empty()) {
+ loggers_.push_back(&android::base::StdioLogger);
+ }
+ }
+ void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+ const char* file, unsigned int line, const char* message) {
+ for (auto&& logger : loggers_) {
+ logger(id, severity, tag, file, line, message);
+ }
+ }
+
+ private:
+ std::vector<android::base::LogFunction> loggers_;
+};
+
bool MergeCmdHandler(int argc, char** argv) {
auto begin = std::chrono::steady_clock::now();
- bool log_to_logcat = false;
- for (int i = 2; i < argc; ++i) {
- if (argv[i] == "--logcat"s) {
- log_to_logcat = true;
- }
- }
- if (log_to_logcat) {
- android::base::InitLogging(argv);
- } else {
- android::base::InitLogging(argv, &android::base::StdioLogger);
- }
+ // 'snapshotctl merge' is stripped away from arguments to
+ // Logger.
+ android::base::InitLogging(argv, MergeCmdLogger(argc - 2, argv + 2));
auto state = SnapshotManager::New()->InitiateMergeAndWait();
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
index 3ab0645..5dbe352 100644
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -1,2 +1,2 @@
on property:sys.boot_completed=1
- exec_background - root root -- /system/bin/snapshotctl merge --logcat
+ exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 3a64448..3318b33 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -15,6 +15,10 @@
#include "utility.h"
#include <errno.h>
+#include <time.h>
+
+#include <iomanip>
+#include <sstream>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -155,5 +159,12 @@
return true;
}
+std::ostream& operator<<(std::ostream& os, const Now&) {
+ struct tm now;
+ time_t t = time(nullptr);
+ localtime_r(&t, &now);
+ return os << std::put_time(&now, "%Y%m%d-%H%M%S");
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index ad46090..90ad0fe 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -15,6 +15,7 @@
#pragma once
#include <functional>
+#include <iostream>
#include <string>
#include <android-base/macros.h>
@@ -120,5 +121,9 @@
// is an open fd to |path|, because that fd has an old view of the file.
bool WriteStringToFileAtomic(const std::string& content, const std::string& path);
+// Writes current time to a given stream.
+struct Now {};
+std::ostream& operator<<(std::ostream& os, const Now&);
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c66f307..e364436 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -474,20 +474,9 @@
if [ 0 != ${counter} ]; then
adb_wait
fi
- if [ -n "`get_property sys.boot.reason`" ]
- then
- vals=`get_property |
- sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
- if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
- then
- sleep 1
- break
- fi
- if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
- then
- sleep 1
- break
- fi
+ if [ "1" = "`get_property sys.boot_completed`" ]; then
+ sleep 1
+ break
fi
fi
counter=`expr ${counter} + 1`
@@ -858,7 +847,7 @@
USB_SERIAL=
[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
grep usb |
- xargs grep -l ${ANDROID_SERIAL}`
+ xargs -r grep -l ${ANDROID_SERIAL}`
USB_ADDRESS=
if [ -n "${USB_SERIAL}" ]; then
USB_ADDRESS=${USB_SERIAL%/serial}
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index 58ed416..d03978d 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <android-base/logging.h>
+
#include "charger.sysprop.h"
#include "healthd_mode_charger.h"
#include "healthd_mode_charger_nops.h"
@@ -23,6 +25,7 @@
#endif
int main(int argc, char** argv) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
if (CHARGER_FORCE_NO_UI || android::sysprop::ChargerProperties::no_ui().value_or(false)) {
return healthd_charger_nops(argc, argv);
} else {
diff --git a/healthd/charger_utils.cpp b/healthd/charger_utils.cpp
index 0cf9df5..8bbfb4e 100644
--- a/healthd/charger_utils.cpp
+++ b/healthd/charger_utils.cpp
@@ -17,50 +17,28 @@
#include "charger_utils.h"
#include <android-base/logging.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.1/IHealth.h>
#include <health/utils.h>
#include <health2impl/Health.h>
-#include <hidl/ServiceManagement.h>
-
-using android::hardware::getPassthroughServiceManager;
-using android::hidl::base::V1_0::IBase;
-using android::hidl::manager::V1_0::IServiceManager;
namespace android {
namespace hardware {
namespace health {
-sp<V2_1::IHealth> GetPassthroughHealthImpl() {
- // Not using getService() because there is no hwservicemanager in charger mode.
- sp<IServiceManager> pm = getPassthroughServiceManager();
- if (pm == nullptr) {
- LOG(WARNING) << "Cannot get passthrough service manager.";
- return nullptr;
- }
- sp<IBase> base = pm->get(V2_0::IHealth::descriptor, "default");
- if (base == nullptr) {
- LOG(WARNING) << "Cannot find passthrough implementation of health 2.0 HAL for instance "
- "'default' on the device.";
- return nullptr;
- }
- sp<V2_1::IHealth> service = V2_1::IHealth::castFrom(base);
- if (service == nullptr) {
- LOG(WARNING)
- << "Cannot cast passthrough implementation of health 2.0 HAL to 2.1 for instance "
- "'default' on the device.";
- return nullptr;
- }
- return service;
-}
-sp<V2_1::IHealth> GetPassthroughHealth() {
- auto impl = GetPassthroughHealthImpl();
- if (impl == nullptr) {
+sp<V2_1::IHealth> GetHealthServiceOrDefault() {
+ // No need to use get_health_service from libhealthhalutils that
+ // checks for "backup" instance provided by healthd, since
+ // V2_1::implementation::Health does the same thing.
+ sp<V2_1::IHealth> service = V2_1::IHealth::getService();
+ if (service != nullptr) {
+ LOG(INFO) << "Charger uses health HAL service.";
+ } else {
LOG(WARNING) << "Charger uses system defaults.";
auto config = std::make_unique<healthd_config>();
InitHealthdConfig(config.get());
- impl = new V2_1::implementation::Health(std::move(config));
+ service = new V2_1::implementation::Health(std::move(config));
}
- return impl;
+ return service;
}
} // namespace health
diff --git a/healthd/charger_utils.h b/healthd/charger_utils.h
index f96e827..39d8aab 100644
--- a/healthd/charger_utils.h
+++ b/healthd/charger_utils.h
@@ -21,7 +21,9 @@
namespace android {
namespace hardware {
namespace health {
-sp<V2_1::IHealth> GetPassthroughHealth();
+// Return health HAL service. If it is not supported on the device (with
+// VINTF checks), return a default passthrough implementation.
+sp<V2_1::IHealth> GetHealthServiceOrDefault();
} // namespace health
} // namespace hardware
} // namespace android
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 7d844c9..386ba1a 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -60,7 +60,7 @@
using namespace android;
using android::hardware::Return;
-using android::hardware::health::GetPassthroughHealth;
+using android::hardware::health::GetHealthServiceOrDefault;
using android::hardware::health::HealthLoop;
using android::hardware::health::V1_0::BatteryStatus;
using android::hardware::health::V2_0::Result;
@@ -742,6 +742,6 @@
}
}
- Charger charger(GetPassthroughHealth());
+ Charger charger(GetHealthServiceOrDefault());
return charger.StartLoop();
}
diff --git a/healthd/healthd_mode_charger_nops.cpp b/healthd/healthd_mode_charger_nops.cpp
index 13e7348..9fe381e 100644
--- a/healthd/healthd_mode_charger_nops.cpp
+++ b/healthd/healthd_mode_charger_nops.cpp
@@ -20,10 +20,10 @@
#include "charger_utils.h"
-using android::hardware::health::GetPassthroughHealth;
+using android::hardware::health::GetHealthServiceOrDefault;
using android::hardware::health::V2_1::implementation::HalHealthLoop;
int healthd_charger_nops(int /* argc */, char** /* argv */) {
- HalHealthLoop charger("charger", GetPassthroughHealth());
+ HalHealthLoop charger("charger", GetHealthServiceOrDefault());
return charger.StartLoop();
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d8c4843..21663e6 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <chrono>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -29,6 +30,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
@@ -45,7 +47,9 @@
#include "uevent_listener.h"
#include "util.h"
+using android::base::ReadFileToString;
using android::base::Split;
+using android::base::StringPrintf;
using android::base::Timer;
using android::fiemap::IImageManager;
using android::fs_mgr::AvbHandle;
@@ -95,6 +99,7 @@
void GetDmLinearMetadataDevice(std::set<std::string>* devices);
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
void UseDsuIfPresent();
+ void PreloadAvbKeys();
ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
@@ -110,6 +115,9 @@
std::string super_partition_name_;
std::unique_ptr<DeviceHandler> device_handler_;
UeventListener uevent_listener_;
+ // Reads all AVB keys before chroot into /system, as they might be used
+ // later when mounting other partitions, e.g., /vendor and /product.
+ std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
};
class FirstStageMountVBootV1 : public FirstStageMount {
@@ -508,11 +516,57 @@
return mounted;
}
+void FirstStageMount::PreloadAvbKeys() {
+ for (const auto& entry : fstab_) {
+ // No need to cache the key content if it's empty, or is already cached.
+ if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
+ continue;
+ }
+
+ // Determines all key paths first.
+ std::vector<std::string> key_paths;
+ if (is_dir(entry.avb_keys.c_str())) { // fstab_keys might be a dir, e.g., /avb.
+ const char* avb_key_dir = entry.avb_keys.c_str();
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
+ if (!dir) {
+ LOG(ERROR) << "Failed to opendir: " << dir;
+ continue;
+ }
+ // Gets all key pathes under the dir.
+ struct dirent* de;
+ while ((de = readdir(dir.get()))) {
+ if (de->d_type != DT_REG) continue;
+ std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
+ key_paths.emplace_back(std::move(full_path));
+ }
+ std::sort(key_paths.begin(), key_paths.end());
+ } else {
+ // avb_keys are key paths separated by ":", if it's not a dir.
+ key_paths = Split(entry.avb_keys, ":");
+ }
+
+ // Reads the key content then cache it.
+ std::vector<std::string> key_blobs;
+ for (const auto& path : key_paths) {
+ std::string key_value;
+ if (!ReadFileToString(path, &key_value)) {
+ continue;
+ }
+ key_blobs.emplace_back(std::move(key_value));
+ }
+
+ // Maps entry.avb_keys to actual key blobs.
+ preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
+ }
+}
+
// If system is in the fstab then we're not a system-as-root device, and in
// this case, we mount system first then pivot to it. From that point on,
// we are effectively identical to a system-as-root device.
bool FirstStageMount::TrySwitchSystemAsRoot() {
UseDsuIfPresent();
+ // Preloading all AVB keys from the ramdisk before switching root to /system.
+ PreloadAvbKeys();
auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
return entry.mount_point == "/system";
@@ -776,7 +830,8 @@
<< fstab_entry->mount_point;
return true; // Returns true to mount the partition directly.
} else {
- auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
+ auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
+ *fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
if (!avb_standalone_handle) {
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
// Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 1d431e3..3f81792 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -208,7 +208,7 @@
// If the property is not set, it defaults to none, in which case there are no keycodes
// for this service.
- if (expanded == "none") {
+ if (*expanded == "none") {
return {};
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 3f3dbd7..3f08535 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -43,12 +43,12 @@
{
"Name": "UClampMin",
"Controller": "cpu",
- "File": "cpu.util.min"
+ "File": "cpu.uclamp.min"
},
{
"Name": "UClampMax",
"Controller": "cpu",
- "File": "cpu.util.max"
+ "File": "cpu.uclamp.max"
}
],
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index 72eb0e9..2171aa4 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -32,7 +32,7 @@
],
export_include_dirs: ["include"],
shared_libs: [
- //TODO: use libbinder_ndk.
+ //TODO: use libbinder_ndk. Remove libservices.
"libbinder",
"libstatssocket",
"libservices",
@@ -40,5 +40,12 @@
static_libs: [
"liblog",
"libutils",
- ]
+ ],
+ // enumerate stable entry points for APEX use
+ stubs: {
+ symbol_file: "libstatspull.map.txt",
+ versions: [
+ "30",
+ ],
+ },
}
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
index b779ac9..ad9b04e 100644
--- a/libstats/pull/include/stats_pull_atom_callback.h
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -15,41 +15,122 @@
*/
#pragma once
+#include <stats_event.h>
+
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
-/*
- * Metadata for registering a stats_pull_atom_callback.
+
+/**
+ * Opaque struct representing the metadata for registering an AStatsManager_PullAtomCallback.
*/
-typedef struct pull_atom_metadata {
- int64_t cool_down_ns;
- int64_t timeout_ns;
- int32_t* additive_fields;
- int32_t additive_fields_size;
-} pull_atom_metadata;
+struct AStatsManager_PullAtomMetadata;
+typedef struct AStatsManager_PullAtomMetadata AStatsManager_PullAtomMetadata;
-typedef struct pulled_stats_event_list pulled_stats_event_list;
+/**
+ * Allocate and initialize new PullAtomMetadata.
+ *
+ * Must call AStatsManager_PullAtomMetadata_release to free the memory.
+ */
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain();
-typedef int32_t status_pull_atom_return_t;
+/**
+ * Frees the memory held by this PullAtomMetadata
+ *
+ * After calling this, the PullAtomMetadata must not be used or modified in any way.
+ */
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata);
+/**
+ * Set the cool down time of the pull in nanoseconds. If two successive pulls are issued
+ * within the cool down, a cached version of the first will be used for the second.
+ */
+void AStatsManager_PullAtomMetadata_setCoolDownNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_ns);
+
+/**
+ * Set the maximum time the pull can take in nanoseconds.
+ */
+void AStatsManager_PullAtomMetadata_setTimeoutNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_ns);
+
+/**
+ * Set the additive fields of this pulled atom.
+ *
+ * This is only applicable for atoms which have a uid field. When tasks are run in
+ * isolated processes, the data will be attributed to the host uid. Additive fields
+ * will be combined when the non-additive fields are the same.
+ */
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int* additive_fields, int num_fields);
+
+/**
+ * Return codes for the result of a pull.
+ */
+typedef int32_t AStatsManager_PullAtomCallbackReturn;
enum {
- STATS_PULL_SUCCESS = 0,
- STATS_PULL_SKIP = 1,
+ // Value indicating that this pull was successful and that the result should be used.
+ AStatsManager_PULL_SUCCESS = 0,
+ // Value indicating that this pull was unsuccessful and that the result should not be used.
+ AStatsManager_PULL_SKIP = 1,
};
-typedef status_pull_atom_return_t (*stats_pull_atom_callback_t)(int32_t atom_tag,
- pulled_stats_event_list* data,
- void* cookie);
+/**
+ * Opaque struct representing a list of AStatsEvent objects.
+ */
+struct AStatsEventList;
+typedef struct AStatsEventList AStatsEventList;
-struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data);
+/**
+ * Appends and returns an AStatsEvent to the end of the AStatsEventList.
+ *
+ * If an AStatsEvent is obtained in this manner, the memory is internally managed and
+ * AStatsEvent_release does not need to be called. The lifetime of the AStatsEvent is that of the
+ * AStatsEventList.
+ *
+ * The AStatsEvent does still need to be built by calling AStatsEvent_build.
+ */
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data);
-void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t callback,
- pull_atom_metadata* metadata, void* cookie);
+/**
+ * Callback interface for pulling atoms requested by the stats service.
+ *
+ * \param atom_tag the tag of the atom to pull.
+ * \param data an output parameter in which the caller should fill the results of the pull. This
+ * param cannot be NULL and it's lifetime is as long as the execution of the callback.
+ * It must not be accessed or modified after returning from the callback.
+ * \param cookie the opaque pointer passed in AStatsManager_registerPullAtomCallback.
+ * \return AStatsManager_PULL_SUCCESS if the pull was successful, or AStatsManager_PULL_SKIP if not.
+ */
+typedef AStatsManager_PullAtomCallbackReturn (*AStatsManager_PullAtomCallback)(
+ int32_t atom_tag, AStatsEventList* data, void* cookie);
+/**
+ * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke the callback when the stats service determines that this atom needs to be
+ * pulled.
+ *
+ * \param atom_tag The tag of the atom for this pull atom callback.
+ * \param metadata Optional metadata specifying the timeout, cool down time, and
+ * additive fields for mapping isolated to host uids.
+ * This param is nullable, in which case defaults will be used.
+ * \param callback The callback to be invoked when the stats service pulls the atom.
+ * \param cookie A pointer that will be passed back to the callback.
+ * It has no meaning to statsd.
+ */
+void AStatsManager_registerPullAtomCallback(int32_t atom_tag,
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata* metadata, void* cookie);
-void unregister_stats_pull_atom_callback(int32_t atom_tag);
+/**
+ * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
+ * pulls will still occur.
+ *
+ * \param atomTag The tag of the atom of which to unregister
+ */
+void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag);
#ifdef __cplusplus
}
diff --git a/libstats/pull/libstatspull.map.txt b/libstats/pull/libstatspull.map.txt
new file mode 100644
index 0000000..dc3fd8b
--- /dev/null
+++ b/libstats/pull/libstatspull.map.txt
@@ -0,0 +1,13 @@
+LIBSTATSPULL {
+ global:
+ AStatsManager_PullAtomMetadata_obtain; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_release; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setCoolDownNs; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setTimeoutNs; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setAdditiveFields; # apex # introduced=30
+ AStatsEventList_addStatsEvent; # apex # introduced=30
+ AStatsManager_registerPullAtomCallback; # apex # introduced=30
+ AStatsManager_unregisterPullAtomCallback; # apex # introduced=30
+ local:
+ *;
+};
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
index e8fc2ea..9c497b8 100644
--- a/libstats/pull/stats_pull_atom_callback.cpp
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -28,12 +28,12 @@
#include <thread>
-struct pulled_stats_event_list {
- std::vector<stats_event*> data;
+struct AStatsEventList {
+ std::vector<AStatsEvent*> data;
};
-struct stats_event* add_stats_event_to_pull_data(pulled_stats_event_list* pull_data) {
- struct stats_event* event = stats_event_obtain();
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
+ AStatsEvent* event = AStatsEvent_obtain();
pull_data->data.push_back(event);
return event;
}
@@ -41,9 +41,42 @@
static const int64_t DEFAULT_COOL_DOWN_NS = 1000000000LL; // 1 second.
static const int64_t DEFAULT_TIMEOUT_NS = 10000000000LL; // 10 seconds.
+struct AStatsManager_PullAtomMetadata {
+ int64_t cool_down_ns;
+ int64_t timeout_ns;
+ std::vector<int32_t> additive_fields;
+};
+
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
+ AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
+ metadata->cool_down_ns = DEFAULT_COOL_DOWN_NS;
+ metadata->timeout_ns = DEFAULT_TIMEOUT_NS;
+ metadata->additive_fields = std::vector<int32_t>();
+ return metadata;
+}
+
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
+ delete metadata;
+}
+
+void AStatsManager_PullAtomMetadata_setCoolDownNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_ns) {
+ metadata->cool_down_ns = cool_down_ns;
+}
+
+void AStatsManager_PullAtomMetadata_setTimeoutNs(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_ns) {
+ metadata->timeout_ns = timeout_ns;
+}
+
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int* additive_fields, int num_fields) {
+ metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
+}
+
class StatsPullAtomCallbackInternal : public android::os::BnPullAtomCallback {
public:
- StatsPullAtomCallbackInternal(const stats_pull_atom_callback_t callback, void* cookie,
+ StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
const int64_t coolDownNs, const int64_t timeoutNs,
const std::vector<int32_t> additiveFields)
: mCallback(callback),
@@ -55,15 +88,16 @@
::android::binder::Status onPullAtom(
int32_t atomTag,
const ::android::sp<::android::os::IPullAtomResultReceiver>& resultReceiver) override {
- pulled_stats_event_list statsEventList;
+ AStatsEventList statsEventList;
+ statsEventList.data.clear();
int successInt = mCallback(atomTag, &statsEventList, mCookie);
- bool success = successInt == STATS_PULL_SUCCESS;
+ bool success = successInt == AStatsManager_PULL_SUCCESS;
// Convert stats_events into StatsEventParcels.
std::vector<android::util::StatsEventParcel> parcels;
for (int i = 0; i < statsEventList.data.size(); i++) {
size_t size;
- uint8_t* buffer = stats_event_get_buffer(statsEventList.data[i], &size);
+ uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
android::util::StatsEventParcel p;
// vector.assign() creates a copy, but this is inevitable unless
@@ -74,7 +108,7 @@
resultReceiver->pullFinished(atomTag, success, parcels);
for (int i = 0; i < statsEventList.data.size(); i++) {
- stats_event_release(statsEventList.data[i]);
+ AStatsEvent_release(statsEventList.data[i]);
}
return android::binder::Status::ok();
}
@@ -84,7 +118,7 @@
const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
private:
- const stats_pull_atom_callback_t mCallback;
+ const AStatsManager_PullAtomCallback mCallback;
void* mCookie;
const int64_t mCoolDownNs;
const int64_t mTimeoutNs;
@@ -165,15 +199,16 @@
statsService->unregisterNativePullAtomCallback(atomTag);
}
-void register_stats_pull_atom_callback(int32_t atom_tag, stats_pull_atom_callback_t callback,
- pull_atom_metadata* metadata, void* cookie) {
+void AStatsManager_registerPullAtomCallback(int32_t atom_tag,
+ AStatsManager_PullAtomCallback callback,
+ AStatsManager_PullAtomMetadata* metadata,
+ void* cookie) {
int64_t coolDownNs = metadata == nullptr ? DEFAULT_COOL_DOWN_NS : metadata->cool_down_ns;
int64_t timeoutNs = metadata == nullptr ? DEFAULT_TIMEOUT_NS : metadata->timeout_ns;
std::vector<int32_t> additiveFields;
- if (metadata != nullptr && metadata->additive_fields != nullptr) {
- additiveFields.assign(metadata->additive_fields,
- metadata->additive_fields + metadata->additive_fields_size);
+ if (metadata != nullptr) {
+ additiveFields = metadata->additive_fields;
}
android::sp<StatsPullAtomCallbackInternal> callbackBinder = new StatsPullAtomCallbackInternal(
@@ -189,7 +224,7 @@
registerThread.detach();
}
-void unregister_stats_pull_atom_callback(int32_t atom_tag) {
+void AStatsManager_unregisterPullAtomCallback(int32_t atom_tag) {
{
std::lock_guard<std::mutex> lg(pullAtomMutex);
// Always remove the puller from our map.
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index edfa070..de458b3 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -38,7 +38,7 @@
// definitions of static class variables
bool StatsEventCompat::mAttemptedLoad = false;
-struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
+void* StatsEventCompat::mStatsEventApi = nullptr;
std::mutex StatsEventCompat::mLoadLock;
StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
@@ -49,7 +49,8 @@
if (!mAttemptedLoad) {
void* handle = dlopen("libstatssocket.so", RTLD_NOW);
if (handle) {
- mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+ // mStatsEventApi = (struct AStatsEvent_apiTable*)dlsym(handle,
+ // "table");
} else {
ALOGE("dlopen failed: %s\n", dlerror());
}
@@ -58,19 +59,19 @@
}
if (mStatsEventApi) {
- mEventR = mStatsEventApi->obtain();
+ // mEventR = mStatsEventApi->obtain();
} else if (!mPlatformAtLeastR) {
mEventQ << android::elapsedRealtimeNano();
}
}
StatsEventCompat::~StatsEventCompat() {
- if (mStatsEventApi) mStatsEventApi->release(mEventR);
+ // if (mStatsEventApi) mStatsEventApi->release(mEventR);
}
void StatsEventCompat::setAtomId(int32_t atomId) {
if (mStatsEventApi) {
- mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
+ // mStatsEventApi->setAtomId(mEventR, (uint32_t)atomId);
} else if (!mPlatformAtLeastR) {
mEventQ << atomId;
}
@@ -78,7 +79,7 @@
void StatsEventCompat::writeInt32(int32_t value) {
if (mStatsEventApi) {
- mStatsEventApi->write_int32(mEventR, value);
+ // mStatsEventApi->writeInt32(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -86,7 +87,7 @@
void StatsEventCompat::writeInt64(int64_t value) {
if (mStatsEventApi) {
- mStatsEventApi->write_int64(mEventR, value);
+ // mStatsEventApi->writeInt64(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -94,7 +95,7 @@
void StatsEventCompat::writeFloat(float value) {
if (mStatsEventApi) {
- mStatsEventApi->write_float(mEventR, value);
+ // mStatsEventApi->writeFloat(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -102,7 +103,7 @@
void StatsEventCompat::writeBool(bool value) {
if (mStatsEventApi) {
- mStatsEventApi->write_bool(mEventR, value);
+ // mStatsEventApi->writeBool(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -110,7 +111,7 @@
void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
if (mStatsEventApi) {
- mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
+ // mStatsEventApi->writeByteArray(mEventR, (const uint8_t*)buffer, length);
} else if (!mPlatformAtLeastR) {
mEventQ.AppendCharArray(buffer, length);
}
@@ -120,7 +121,7 @@
if (value == nullptr) value = "";
if (mStatsEventApi) {
- mStatsEventApi->write_string8(mEventR, value);
+ // mStatsEventApi->writeString(mEventR, value);
} else if (!mPlatformAtLeastR) {
mEventQ << value;
}
@@ -129,8 +130,8 @@
void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
const vector<const char*>& tags) {
if (mStatsEventApi) {
- mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
- (uint8_t)numUids);
+ // mStatsEventApi->writeAttributionChain(mEventR, (const uint32_t*)uids, tags.data(),
+ // (uint8_t)numUids);
} else if (!mPlatformAtLeastR) {
mEventQ.begin();
for (size_t i = 0; i < numUids; i++) {
@@ -148,26 +149,8 @@
const map<int, int64_t>& int64Map,
const map<int, const char*>& stringMap,
const map<int, float>& floatMap) {
- if (mStatsEventApi) {
- vector<struct key_value_pair> pairs;
-
- for (const auto& it : int32Map) {
- pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
- }
- for (const auto& it : int64Map) {
- pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
- }
- for (const auto& it : stringMap) {
- pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
- }
- for (const auto& it : floatMap) {
- pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
- }
-
- mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
- }
-
- else if (!mPlatformAtLeastR) {
+ // Key value pairs are not supported with AStatsEvent.
+ if (!mPlatformAtLeastR) {
mEventQ.begin();
writeKeyValuePairMap(int32Map);
writeKeyValuePairMap(int64Map);
@@ -194,19 +177,25 @@
template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
- if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+ // Workaround for unused params.
+ (void)annotationId;
+ (void)value;
+ // if (mStatsEventApi) mStatsEventApi->addBoolAnnotation(mEventR, annotationId, value);
// Don't do anything if on Q.
}
void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
- if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+ // Workaround for unused params.
+ (void)annotationId;
+ (void)value;
+ // if (mStatsEventApi) mStatsEventApi->addInt32Annotation(mEventR, annotationId, value);
// Don't do anything if on Q.
}
int StatsEventCompat::writeToSocket() {
if (mStatsEventApi) {
- mStatsEventApi->build(mEventR);
- return mStatsEventApi->write(mEventR);
+ // mStatsEventApi->build(mEventR);
+ // return mStatsEventApi->write(mEventR);
}
if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
index a8cde68..ad423a1 100644
--- a/libstats/push_compat/include/StatsEventCompat.h
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -57,10 +57,11 @@
const static bool mPlatformAtLeastR;
static bool mAttemptedLoad;
static std::mutex mLoadLock;
- static struct stats_event_api_table* mStatsEventApi;
+ // static struct AStatsEvent_apiTable* mStatsEventApi;
+ static void* mStatsEventApi;
// non-static member variables
- struct stats_event* mEventR = nullptr;
+ AStatsEvent* mEventR = nullptr;
stats_event_list mEventQ;
template <class T>
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 9fd9fbc..f36b214 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -45,7 +45,7 @@
stubs: {
symbol_file: "libstatssocket.map.txt",
versions: [
- "1",
+ "30",
],
}
}
@@ -92,5 +92,5 @@
"liblog",
"libutils",
],
- test_suites: ["device_tests"],
+ test_suites: ["device-tests"],
}
diff --git a/libstats/socket/TEST_MAPPING b/libstats/socket/TEST_MAPPING
new file mode 100644
index 0000000..0224998
--- /dev/null
+++ b/libstats/socket/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit" : [
+ {
+ "name" : "libstatssocket_test"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
index 9488168..3fc6e55 100644
--- a/libstats/socket/benchmark/stats_event_benchmark.cpp
+++ b/libstats/socket/benchmark/stats_event_benchmark.cpp
@@ -17,14 +17,14 @@
#include "benchmark/benchmark.h"
#include "stats_event.h"
-static struct stats_event* constructStatsEvent() {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
+static AStatsEvent* constructStatsEvent() {
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
// randomly sample atom size
int numElements = rand() % 800;
for (int i = 0; i < numElements; i++) {
- stats_event_write_int32(event, i);
+ AStatsEvent_writeInt32(event, i);
}
return event;
@@ -32,10 +32,10 @@
static void BM_stats_event_truncate_buffer(benchmark::State& state) {
while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
+ AStatsEvent* event = constructStatsEvent();
+ AStatsEvent_build(event);
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
}
}
@@ -43,11 +43,11 @@
static void BM_stats_event_full_buffer(benchmark::State& state) {
while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_truncate_buffer(event, false);
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
+ AStatsEvent* event = constructStatsEvent();
+ AStatsEvent_truncateBuffer(event, false);
+ AStatsEvent_build(event);
+ AStatsEvent_write(event);
+ AStatsEvent_release(event);
}
}
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 080e957..6a2d9cd 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -26,17 +26,17 @@
* This code defines and encapsulates the socket protocol.
*
* Usage:
- * struct stats_event* event = stats_event_obtain();
+ * AStatsEvent* event = AStatsEvent_obtain();
*
- * stats_event_set_atom_id(event, atomId);
- * stats_event_write_int32(event, 24);
- * stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
- * stats_event_add_int32_annotation(event, 2, 128);
- * stats_event_write_float(event, 2.0);
+ * AStatsEvent_setAtomId(event, atomId);
+ * AStatsEvent_writeInt32(event, 24);
+ * AStatsEvent_addBoolAnnotation(event, 1, true); // annotations apply to the previous field
+ * AStatsEvent_addInt32Annotation(event, 2, 128);
+ * AStatsEvent_writeFloat(event, 2.0);
*
- * stats_event_build(event);
- * stats_event_write(event);
- * stats_event_release(event);
+ * AStatsEvent_build(event);
+ * AStatsEvent_write(event);
+ * AStatsEvent_release(event);
*
* Notes:
* (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
@@ -47,115 +47,118 @@
* (e) All strings should be encoded using UTF8.
*/
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
#ifdef __cplusplus
extern "C" {
#endif // __CPLUSPLUS
-struct stats_event;
-
-/* SYSTEM API */
-struct stats_event* stats_event_obtain();
-// The build function can be called multiple times without error. If the event
-// has been built before, this function is a no-op.
-void stats_event_build(struct stats_event* event);
-int stats_event_write(struct stats_event* event);
-void stats_event_release(struct stats_event* event);
-
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
-
-void stats_event_write_int32(struct stats_event* event, int32_t value);
-void stats_event_write_int64(struct stats_event* event, int64_t value);
-void stats_event_write_float(struct stats_event* event, float value);
-void stats_event_write_bool(struct stats_event* event, bool value);
-
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
-
-// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* value);
-
-// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes);
-
-/* key_value_pair struct can be constructed as follows:
- * struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
- * .stringValue = buf};
+/**
+ * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
+ * statsd.
*/
-struct key_value_pair {
- int32_t key;
- uint8_t valueType; // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
- union {
- int32_t int32Value;
- int64_t int64Value;
- float floatValue;
- const char* stringValue; // must be null terminated
- };
-};
+struct AStatsEvent;
+typedef struct AStatsEvent AStatsEvent;
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs);
+/**
+ * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
+ * the allocated memory.
+ */
+AStatsEvent* AStatsEvent_obtain();
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value);
+/**
+ * Builds and finalizes the StatsEvent.
+ *
+ * After this function, the StatsEvent must not be modified in any way other than calling release or
+ * write. Build must be always be called before AStatsEvent_write.
+ *
+ * Build can be called multiple times without error.
+ * If the event has been built before, this function is a no-op.
+ */
+void AStatsEvent_build(AStatsEvent* event);
-uint32_t stats_event_get_atom_id(struct stats_event* event);
+/**
+ * Writes the StatsEvent to the stats log.
+ *
+ * After calling this, AStatsEvent_release must be called,
+ * and is the only function that can be safely called.
+ */
+int AStatsEvent_write(AStatsEvent* event);
+
+/**
+ * Frees the memory held by this StatsEvent
+ *
+ * After calling this, the StatsEvent must not be used or modified in any way.
+ */
+void AStatsEvent_release(AStatsEvent* event);
+
+/**
+ * Sets the atom id for this StatsEvent.
+ **/
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
+
+/**
+ * Writes an int32_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
+
+/**
+ * Writes an int64_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
+
+/**
+ * Writes a float field to this StatsEvent.
+ **/
+void AStatsEvent_writeFloat(AStatsEvent* event, float value);
+
+/**
+ * Write a bool field to this StatsEvent.
+ **/
+void AStatsEvent_writeBool(AStatsEvent* event, bool value);
+
+/**
+ * Write a byte array field to this StatsEvent.
+ **/
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
+
+/**
+ * Write a string field to this StatsEvent.
+ *
+ * The string must be null-terminated.
+ **/
+void AStatsEvent_writeString(AStatsEvent* event, const char* value);
+
+/**
+ * Write an attribution chain field to this StatsEvent.
+ *
+ * The sizes of uids and tags must be equal. The AttributionNode at position i is
+ * made up of uids[i] and tags[i].
+ *
+ * \param uids array of uids in the attribution chain.
+ * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
+ * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
+ * the uids and the tags.
+ **/
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes);
+
+/**
+ * Write a bool annotation for the previous field written.
+ **/
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
+
+/**
+ * Write an integer annotation for the previous field written.
+ **/
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
+
+// Internal/test APIs. Should not be exposed outside of the APEX.
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
// Size is an output parameter.
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
-uint32_t stats_event_get_errors(struct stats_event* event);
-
-// This table is used by StatsEventCompat to access the stats_event API.
-struct stats_event_api_table {
- struct stats_event* (*obtain)(void);
- void (*build)(struct stats_event*);
- int (*write)(struct stats_event*);
- void (*release)(struct stats_event*);
- void (*set_atom_id)(struct stats_event*, uint32_t);
- void (*write_int32)(struct stats_event*, int32_t);
- void (*write_int64)(struct stats_event*, int64_t);
- void (*write_float)(struct stats_event*, float);
- void (*write_bool)(struct stats_event*, bool);
- void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
- void (*write_string8)(struct stats_event*, const char*);
- void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
- uint8_t);
- void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
- void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
- void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
- uint32_t (*get_atom_id)(struct stats_event*);
- uint8_t* (*get_buffer)(struct stats_event*, size_t*);
- uint32_t (*get_errors)(struct stats_event*);
-};
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
+uint32_t AStatsEvent_getErrors(AStatsEvent* event);
// exposed for benchmarking only
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+void AStatsEvent_truncateBuffer(struct AStatsEvent* event, bool truncate);
#ifdef __cplusplus
}
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index 55bfbda..e2e7ae3 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -1,23 +1,19 @@
LIBSTATSSOCKET {
global:
- stats_event_obtain; # apex # introduced=1
- stats_event_build; # apex # introduced=1
- stats_event_write; # apex # introduced=1
- stats_event_release; # apex # introduced=1
- stats_event_set_atom_id; # apex # introduced=1
- stats_event_write_int32; # apex # introduced=1
- stats_event_write_int64; # apex # introduced=1
- stats_event_write_float; # apex # introduced=1
- stats_event_write_bool; # apex # introduced=1
- stats_event_write_byte_array; # apex # introduced=1
- stats_event_write_string8; # apex # introduced=1
- stats_event_write_attribution_chain; # apex # introduced=1
- stats_event_write_key_value_pairs; # apex # introduced=1
- stats_event_add_bool_annotation; # apex # introduced=1
- stats_event_add_int32_annotation; # apex # introduced=1
- stats_event_get_atom_id; # apex # introduced=1
- stats_event_get_buffer; # apex # introduced=1
- stats_event_get_errors; # apex # introduced=1
+ AStatsEvent_obtain; # apex # introduced=30
+ AStatsEvent_build; # apex # introduced=30
+ AStatsEvent_write; # apex # introduced=30
+ AStatsEvent_release; # apex # introduced=30
+ AStatsEvent_setAtomId; # apex # introduced=30
+ AStatsEvent_writeInt32; # apex # introduced=30
+ AStatsEvent_writeInt64; # apex # introduced=30
+ AStatsEvent_writeFloat; # apex # introduced=30
+ AStatsEvent_writeBool; # apex # introduced=30
+ AStatsEvent_writeByteArray; # apex # introduced=30
+ AStatsEvent_writeString; # apex # introduced=30
+ AStatsEvent_writeAttributionChain; # apex # introduced=30
+ AStatsEvent_addBoolAnnotation; # apex # introduced=30
+ AStatsEvent_addInt32Annotation; # apex # introduced=30
local:
*;
};
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 15039c6..5f77558 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -35,9 +35,36 @@
#define MAX_ANNOTATION_COUNT 15
#define MAX_BYTE_VALUE 127 // parsing side requires that lengths fit in 7 bits
-// The stats_event struct holds the serialized encoding of an event
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+// The AStatsEvent struct holds the serialized encoding of an event
// within a buf. Also includes other required fields.
-struct stats_event {
+struct AStatsEvent {
uint8_t* buf;
size_t lastFieldPos; // location of last field within the buf
size_t size; // number of valid bytes within buffer
@@ -55,8 +82,8 @@
return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
}
-struct stats_event* stats_event_obtain() {
- struct stats_event* event = malloc(sizeof(struct stats_event));
+AStatsEvent* AStatsEvent_obtain() {
+ AStatsEvent* event = malloc(sizeof(AStatsEvent));
event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
event->buf[0] = OBJECT_TYPE;
event->atomId = 0;
@@ -76,12 +103,12 @@
return event;
}
-void stats_event_release(struct stats_event* event) {
+void AStatsEvent_release(AStatsEvent* event) {
free(event->buf);
free(event);
}
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
event->atomId = atomId;
event->buf[POS_ATOM_ID] = INT32_TYPE;
memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
@@ -89,7 +116,7 @@
}
// Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(struct stats_event* event, size_t size) {
+static bool overflows(AStatsEvent* event, size_t size) {
if (event->size + size > MAX_EVENT_PAYLOAD) {
event->errors |= ERROR_OVERFLOW;
return true;
@@ -99,39 +126,39 @@
// Side-effect: all append functions increment event->size if there is
// sufficient space within the buffer to place the value
-static void append_byte(struct stats_event* event, uint8_t value) {
+static void append_byte(AStatsEvent* event, uint8_t value) {
if (!overflows(event, sizeof(value))) {
event->buf[event->size] = value;
event->size += sizeof(value);
}
}
-static void append_bool(struct stats_event* event, bool value) {
+static void append_bool(AStatsEvent* event, bool value) {
append_byte(event, (uint8_t)value);
}
-static void append_int32(struct stats_event* event, int32_t value) {
+static void append_int32(AStatsEvent* event, int32_t value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(value);
}
}
-static void append_int64(struct stats_event* event, int64_t value) {
+static void append_int64(AStatsEvent* event, int64_t value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(value);
}
}
-static void append_float(struct stats_event* event, float value) {
+static void append_float(AStatsEvent* event, float value) {
if (!overflows(event, sizeof(value))) {
memcpy(&event->buf[event->size], &value, sizeof(value));
event->size += sizeof(float);
}
}
-static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
if (!overflows(event, size)) {
memcpy(&event->buf[event->size], buf, size);
event->size += size;
@@ -139,7 +166,7 @@
}
// Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(struct stats_event* event, const char* buf) {
+static void append_string(AStatsEvent* event, const char* buf) {
size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
if (size == MAX_EVENT_PAYLOAD) {
event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
@@ -150,41 +177,41 @@
append_byte_array(event, (uint8_t*)buf, size);
}
-static void start_field(struct stats_event* event, uint8_t typeId) {
+static void start_field(AStatsEvent* event, uint8_t typeId) {
event->lastFieldPos = event->size;
append_byte(event, typeId);
event->numElements++;
}
-void stats_event_write_int32(struct stats_event* event, int32_t value) {
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
if (event->errors) return;
start_field(event, INT32_TYPE);
append_int32(event, value);
}
-void stats_event_write_int64(struct stats_event* event, int64_t value) {
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
if (event->errors) return;
start_field(event, INT64_TYPE);
append_int64(event, value);
}
-void stats_event_write_float(struct stats_event* event, float value) {
+void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
if (event->errors) return;
start_field(event, FLOAT_TYPE);
append_float(event, value);
}
-void stats_event_write_bool(struct stats_event* event, bool value) {
+void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
if (event->errors) return;
start_field(event, BOOL_TYPE);
append_bool(event, value);
}
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
if (event->errors) return;
start_field(event, BYTE_ARRAY_TYPE);
@@ -193,7 +220,7 @@
}
// Value is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* value) {
+void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
if (event->errors) return;
start_field(event, STRING_TYPE);
@@ -201,8 +228,8 @@
}
// Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes) {
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes) {
if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
if (event->errors) return;
@@ -215,39 +242,8 @@
}
}
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs) {
- if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
- if (event->errors) return;
-
- start_field(event, KEY_VALUE_PAIRS_TYPE);
- append_byte(event, numPairs);
-
- for (uint8_t i = 0; i < numPairs; i++) {
- append_int32(event, pairs[i].key);
- append_byte(event, pairs[i].valueType);
- switch (pairs[i].valueType) {
- case INT32_TYPE:
- append_int32(event, pairs[i].int32Value);
- break;
- case INT64_TYPE:
- append_int64(event, pairs[i].int64Value);
- break;
- case FLOAT_TYPE:
- append_float(event, pairs[i].floatValue);
- break;
- case STRING_TYPE:
- append_string(event, pairs[i].stringValue);
- break;
- default:
- event->errors |= ERROR_INVALID_VALUE_TYPE;
- return;
- }
- }
-}
-
// Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(struct stats_event* event) {
+static void increment_annotation_count(AStatsEvent* event) {
uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
uint32_t newAnnotationCount = oldAnnotationCount + 1;
@@ -260,7 +256,7 @@
event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
}
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
if (event->errors) return;
@@ -271,8 +267,7 @@
increment_annotation_count(event);
}
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value) {
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
if (event->errors) return;
@@ -283,24 +278,24 @@
increment_annotation_count(event);
}
-uint32_t stats_event_get_atom_id(struct stats_event* event) {
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
return event->atomId;
}
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
if (size) *size = event->size;
return event->buf;
}
-uint32_t stats_event_get_errors(struct stats_event* event) {
+uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
return event->errors;
}
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
+void AStatsEvent_truncateBuffer(AStatsEvent* event, bool truncate) {
event->truncate = truncate;
}
-void stats_event_build(struct stats_event* event) {
+void AStatsEvent_build(AStatsEvent* event) {
if (event->built) return;
if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
@@ -327,28 +322,7 @@
event->built = true;
}
-int stats_event_write(struct stats_event* event) {
- stats_event_build(event);
+int AStatsEvent_write(AStatsEvent* event) {
+ AStatsEvent_build(event);
return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
-}
-
-struct stats_event_api_table table = {
- stats_event_obtain,
- stats_event_build,
- stats_event_write,
- stats_event_release,
- stats_event_set_atom_id,
- stats_event_write_int32,
- stats_event_write_int64,
- stats_event_write_float,
- stats_event_write_bool,
- stats_event_write_byte_array,
- stats_event_write_string8,
- stats_event_write_attribution_chain,
- stats_event_write_key_value_pairs,
- stats_event_add_bool_annotation,
- stats_event_add_int32_annotation,
- stats_event_get_atom_id,
- stats_event_get_buffer,
- stats_event_get_errors,
-};
+}
\ No newline at end of file
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index cf0592c..48bf4b8 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -18,6 +18,34 @@
#include <gtest/gtest.h>
#include <utils/SystemClock.h>
+// Keep in sync stats_event.c. Consider moving to separate header file to avoid duplication.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
using std::string;
using std::vector;
@@ -88,17 +116,17 @@
bool boolValue = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_int32(event, int32Value);
- stats_event_write_int64(event, int64Value);
- stats_event_write_float(event, floatValue);
- stats_event_write_bool(event, boolValue);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeInt32(event, int32Value);
+ AStatsEvent_writeInt64(event, int64Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
@@ -120,8 +148,8 @@
checkScalar(&buffer, boolValue);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestStrings) {
@@ -129,14 +157,14 @@
string str = "test_string";
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_string8(event, str.c_str());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeString(event, str.c_str());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -145,8 +173,8 @@
checkString(&buffer, str);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestByteArrays) {
@@ -154,14 +182,14 @@
vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_byte_array(event, message.data(), message.size());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeByteArray(event, message.data(), message.size());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -170,8 +198,8 @@
checkByteArray(&buffer, message);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestAttributionChains) {
@@ -188,14 +216,14 @@
}
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_attribution_chain(event, uids, cTags, numNodes);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -208,60 +236,8 @@
}
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
-}
-
-TEST(StatsEventTest, TestKeyValuePairs) {
- uint32_t atomId = 100;
-
- uint8_t numPairs = 4;
- struct key_value_pair pairs[numPairs];
- pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
- pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
- pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
- string str = "test_key_value_pair_string";
- pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
-
- int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_key_value_pairs(event, pairs, numPairs);
- stats_event_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
- checkScalar(&buffer, numPairs);
-
- // first pair
- checkScalar(&buffer, pairs[0].key);
- checkTypeHeader(&buffer, pairs[0].valueType);
- checkScalar(&buffer, pairs[0].int32Value);
-
- // second pair
- checkScalar(&buffer, pairs[1].key);
- checkTypeHeader(&buffer, pairs[1].valueType);
- checkScalar(&buffer, pairs[1].int64Value);
-
- // third pair
- checkScalar(&buffer, pairs[2].key);
- checkTypeHeader(&buffer, pairs[2].valueType);
- checkScalar(&buffer, pairs[2].floatValue);
-
- // fourth pair
- checkScalar(&buffer, pairs[3].key);
- checkTypeHeader(&buffer, pairs[3].valueType);
- checkString(&buffer, str);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestAnnotations) {
@@ -282,19 +258,19 @@
bool floatAnnotation2Value = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
- stats_event_write_bool(event, boolValue);
- stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
- stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
- stats_event_write_float(event, floatValue);
- stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
- stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
+ AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
+ AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
@@ -312,33 +288,33 @@
checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestNoAtomIdError) {
- struct stats_event* event = stats_event_obtain();
+ AStatsEvent* event = AStatsEvent_obtain();
// Don't set the atom id in order to trigger the error.
- stats_event_build(event);
+ AStatsEvent_build(event);
- uint32_t errors = stats_event_get_errors(event);
+ uint32_t errors = AStatsEvent_getErrors(event);
EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
- stats_event_release(event);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestOverflowError) {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
// Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
// overflow the 4068 byte buffer.
for (int i = 0; i < 1000; i++) {
- stats_event_write_int32(event, 0);
+ AStatsEvent_writeInt32(event, 0);
}
- stats_event_build(event);
+ AStatsEvent_build(event);
- uint32_t errors = stats_event_get_errors(event);
+ uint32_t errors = AStatsEvent_getErrors(event);
EXPECT_NE(errors | ERROR_OVERFLOW, 0);
- stats_event_release(event);
+ AStatsEvent_release(event);
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d7a9c8a..5fbad75 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -165,6 +165,19 @@
chmod 0770 /config/sdcardfs
chown system package_info /config/sdcardfs
+ # Mount binderfs
+ mkdir /dev/binderfs
+ mount binder binder /dev/binderfs stats=global
+ chmod 0755 /dev/binderfs
+
+ symlink /dev/binderfs/binder /dev/binder
+ symlink /dev/binderfs/hwbinder /dev/hwbinder
+ symlink /dev/binderfs/vndbinder /dev/vndbinder
+
+ chmod 0666 /dev/binderfs/hwbinder
+ chmod 0666 /dev/binderfs/binder
+ chmod 0666 /dev/binderfs/vndbinder
+
mkdir /mnt/secure 0700 root root
mkdir /mnt/secure/asec 0700 root root
mkdir /mnt/asec 0755 root system
@@ -600,6 +613,7 @@
mkdir /data/misc/installd 0700 root root
mkdir /data/misc/apexdata 0711 root root
mkdir /data/misc/apexrollback 0700 root root
+ mkdir /data/misc/snapshotctl_log 0770 root root
mkdir /data/preloads 0775 system system encryption=None
@@ -680,10 +694,6 @@
mkdir /data/user/0 0700 system system encryption=None
mount none /data/data /data/user/0 bind rec
- # Special-case /data/media/obb per b/64566063
- mkdir /data/media 0770 media_rw media_rw encryption=None
- mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
-
# A tmpfs directory, which will contain all apps CE DE data directory that
# bind mount from the original source.
chown root root /data_mirror
@@ -721,10 +731,21 @@
wait_for_prop apexd.status ready
perform_apex_config
+ # Special-case /data/media/obb per b/64566063
+ mkdir /data/media 0770 media_rw media_rw encryption=None
+ exec - media_rw media_rw -- /system/bin/chattr +F /data/media
+ mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
+
exec_start derive_sdk
init_user0
+ # Allow apexd to snapshot and restore device encrypted apex data in the case
+ # of a rollback. This should be done immediately after DE_user data keys
+ # are loaded. APEXes should not access this data until this has been
+ # completed.
+ exec_start apexd-snapshotde
+
# Set SELinux security contexts on upgrade or policy update.
restorecon --recursive --skip-ce /data