Merge changes I975ba933,Ica9d211b
* changes:
Add tests for multiton issue
Add GetExecutableDirectory to libbase
diff --git a/init/init.cpp b/init/init.cpp
index 9b14467..bddf005 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -52,6 +52,8 @@
#include <fstream>
#include <memory>
+#include <set>
+#include <vector>
#include "action.h"
#include "bootchart.h"
@@ -700,6 +702,92 @@
return true;
}
+// Creates devices with uevent->partition_name matching one in the in/out
+// partition_names. Note that the partition_names MUST have A/B suffix
+// when A/B is used. Found partitions will then be removed from the
+// partition_names for caller to check which devices are NOT created.
+static void early_device_init(std::set<std::string>* partition_names) {
+ if (partition_names->empty()) {
+ return;
+ }
+ device_init(nullptr, [=](uevent* uevent) -> coldboot_action_t {
+ if (!strncmp(uevent->subsystem, "firmware", 8)) {
+ return COLDBOOT_CONTINUE;
+ }
+
+ // we need platform devices to create symlinks
+ if (!strncmp(uevent->subsystem, "platform", 8)) {
+ return COLDBOOT_CREATE;
+ }
+
+ // Ignore everything that is not a block device
+ if (strncmp(uevent->subsystem, "block", 5)) {
+ return COLDBOOT_CONTINUE;
+ }
+
+ if (uevent->partition_name) {
+ // match partition names to create device nodes for partitions
+ // both partition_names and uevent->partition_name have A/B suffix when A/B is used
+ auto iter = partition_names->find(uevent->partition_name);
+ if (iter != partition_names->end()) {
+ LOG(VERBOSE) << "early_mount: found partition: " << *iter;
+ partition_names->erase(iter);
+ if (partition_names->empty()) {
+ return COLDBOOT_STOP; // found all partitions, stop coldboot
+ } else {
+ return COLDBOOT_CREATE; // create this device and continue to find others
+ }
+ }
+ }
+ // Not found a partition or find an unneeded partition, continue to find others
+ return COLDBOOT_CONTINUE;
+ });
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions, bool* out_need_verity) {
+ std::string meta_partition;
+ out_partitions->clear();
+ *out_need_verity = false;
+
+ for (auto fstab_rec : early_fstab_recs) {
+ // don't allow verifyatboot for early mounted partitions
+ if (fs_mgr_is_verifyatboot(fstab_rec)) {
+ LOG(ERROR) << "early_mount: partitions can't be verified at boot";
+ return false;
+ }
+ // check for verified partitions
+ if (fs_mgr_is_verified(fstab_rec)) {
+ *out_need_verity = true;
+ }
+ // check if verity metadata is on a separate partition and get partition
+ // name from the end of the ->verity_loc path. verity state is not partition
+ // specific, so there must be only 1 additional partition that carries
+ // verity state.
+ if (fstab_rec->verity_loc) {
+ if (!meta_partition.empty()) {
+ LOG(ERROR) << "early_mount: more than one meta partition found: " << meta_partition
+ << ", " << basename(fstab_rec->verity_loc);
+ return false;
+ } else {
+ meta_partition = basename(fstab_rec->verity_loc);
+ }
+ }
+ }
+
+ // includes those early mount partitions and meta_partition (if any)
+ // note that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used
+ for (auto fstab_rec : early_fstab_recs) {
+ out_partitions->emplace(basename(fstab_rec->blk_device));
+ }
+
+ if (!meta_partition.empty()) {
+ out_partitions->emplace(std::move(meta_partition));
+ }
+
+ return true;
+}
+
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
// first check if device tree fstab entries are compatible
@@ -716,122 +804,36 @@
}
// find out fstab records for odm, system and vendor
- // TODO: add std::map<std::string, fstab_rec*> so all required information about
- // them can be gathered at once in a single loop
- fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
- fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
- fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
- if (!odm_rec && !system_rec && !vendor_rec) {
- // nothing to early mount
- return true;
+ std::vector<fstab_rec*> early_fstab_recs;
+ for (auto mount_point : {"/odm", "/system", "/vendor"}) {
+ fstab_rec* fstab_rec = fs_mgr_get_entry_for_mount_point(tab.get(), mount_point);
+ if (fstab_rec != nullptr) {
+ early_fstab_recs.push_back(fstab_rec);
+ }
}
- // don't allow verifyatboot for early mounted partitions
- if ((odm_rec && fs_mgr_is_verifyatboot(odm_rec)) ||
- (system_rec && fs_mgr_is_verifyatboot(system_rec)) ||
- (vendor_rec && fs_mgr_is_verifyatboot(vendor_rec))) {
- LOG(ERROR) << "Early mount partitions can't be verified at boot";
+ // nothing to early mount
+ if (early_fstab_recs.empty()) return true;
+
+ bool need_verity;
+ std::set<std::string> partition_names;
+ // partition_names MUST have A/B suffix when A/B is used
+ if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
return false;
}
- // assume A/B device if we find 'slotselect' in any fstab entry
- bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
- (system_rec && fs_mgr_is_slotselect(system_rec)) ||
- (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
-
- // check for verified partitions
- bool need_verity = ((odm_rec && fs_mgr_is_verified(odm_rec)) ||
- (system_rec && fs_mgr_is_verified(system_rec)) ||
- (vendor_rec && fs_mgr_is_verified(vendor_rec)));
-
- // check if verity metadata is on a separate partition and get partition
- // name from the end of the ->verity_loc path. verity state is not partition
- // specific, so there must be only 1 additional partition that carries
- // verity state.
- std::string meta_partition;
- if (odm_rec && odm_rec->verity_loc) {
- meta_partition = basename(odm_rec->verity_loc);
- } else if (system_rec && system_rec->verity_loc) {
- meta_partition = basename(system_rec->verity_loc);
- } else if (vendor_rec && vendor_rec->verity_loc) {
- meta_partition = basename(vendor_rec->verity_loc);
- }
-
- bool found_odm = !odm_rec;
- bool found_system = !system_rec;
- bool found_vendor = !vendor_rec;
- bool found_meta = meta_partition.empty();
- int count_odm = 0, count_vendor = 0, count_system = 0;
-
+ bool success = false;
// create the devices we need..
- device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
- if (!strncmp(uevent->subsystem, "firmware", 8)) {
- return COLDBOOT_CONTINUE;
- }
+ early_device_init(&partition_names);
- // we need platform devices to create symlinks
- if (!strncmp(uevent->subsystem, "platform", 8)) {
- return COLDBOOT_CREATE;
- }
-
- // Ignore everything that is not a block device
- if (strncmp(uevent->subsystem, "block", 5)) {
- return COLDBOOT_CONTINUE;
- }
-
- coldboot_action_t ret;
- bool create_this_node = false;
- if (uevent->partition_name) {
- // prefix match partition names so we create device nodes for
- // A/B-ed partitions
- if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
-
- // wait twice for A/B-ed partitions
- count_odm++;
- if (!is_ab || count_odm == 2) {
- found_odm = true;
- }
-
- create_this_node = true;
- } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
-
- count_system++;
- if (!is_ab || count_system == 2) {
- found_system = true;
- }
-
- create_this_node = true;
- } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
- count_vendor++;
- if (!is_ab || count_vendor == 2) {
- found_vendor = true;
- }
-
- create_this_node = true;
- } else if (!found_meta && (meta_partition == uevent->partition_name)) {
- LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
- found_meta = true;
- create_this_node = true;
- }
- }
-
- // if we found all other partitions already, create this
- // node and stop coldboot. If this is a prefix matched
- // partition, create device node and continue. For everything
- // else skip the device node
- if (found_meta && found_odm && found_system && found_vendor) {
- ret = COLDBOOT_STOP;
- } else if (create_this_node) {
- ret = COLDBOOT_CREATE;
- } else {
- ret = COLDBOOT_CONTINUE;
- }
-
- return ret;
- });
+ // early_device_init will remove found partitions from partition_names
+ // So if the partition_names is not empty here, means some partitions
+ // are not found
+ if (!partition_names.empty()) {
+ LOG(ERROR) << "early_mount: partition(s) not found: "
+ << android::base::Join(partition_names, ", ");
+ goto done;
+ }
if (need_verity) {
// create /dev/device mapper
@@ -839,10 +841,10 @@
[&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
- bool success = true;
- if (odm_rec && !(success = early_mount_one(odm_rec))) goto done;
- if (system_rec && !(success = early_mount_one(system_rec))) goto done;
- if (vendor_rec && !(success = early_mount_one(vendor_rec))) goto done;
+ for (auto fstab_rec : early_fstab_recs) {
+ if (!early_mount_one(fstab_rec)) goto done;
+ }
+ success = true;
done:
device_close();
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 75e2492..1915ced 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -165,7 +165,7 @@
/* Support Bluetooth legacy hal accessing /sys/class/rfkill */
{ 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
- "system/bin/hw/android.hardware.bluetooth@1.0-service" },
+ "vendor/bin/hw/android.hardware.bluetooth@1.0-service" },
/* A non-privileged zygote that spawns isolated processes for web rendering. */
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 0b0dc09..718d76b 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -46,6 +46,12 @@
suffix: "64",
},
},
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
}
test_libraries = [
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index c5f58b4..ae5c416 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -17,59 +17,61 @@
#include <cutils/multiuser.h>
#include <gtest/gtest.h>
+static constexpr auto ERR_GID = static_cast<gid_t>(-1);
+
TEST(MultiuserTest, TestMerge) {
- EXPECT_EQ(0, multiuser_get_uid(0, 0));
- EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
- EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
- EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
- EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
- EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
- EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
- EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+ EXPECT_EQ(0U, multiuser_get_uid(0, 0));
+ EXPECT_EQ(1000U, multiuser_get_uid(0, 1000));
+ EXPECT_EQ(10000U, multiuser_get_uid(0, 10000));
+ EXPECT_EQ(50000U, multiuser_get_uid(0, 50000));
+ EXPECT_EQ(1000000U, multiuser_get_uid(10, 0));
+ EXPECT_EQ(1001000U, multiuser_get_uid(10, 1000));
+ EXPECT_EQ(1010000U, multiuser_get_uid(10, 10000));
+ EXPECT_EQ(1050000U, multiuser_get_uid(10, 50000));
}
TEST(MultiuserTest, TestSplitUser) {
- EXPECT_EQ(0, multiuser_get_user_id(0));
- EXPECT_EQ(0, multiuser_get_user_id(1000));
- EXPECT_EQ(0, multiuser_get_user_id(10000));
- EXPECT_EQ(0, multiuser_get_user_id(50000));
- EXPECT_EQ(10, multiuser_get_user_id(1000000));
- EXPECT_EQ(10, multiuser_get_user_id(1001000));
- EXPECT_EQ(10, multiuser_get_user_id(1010000));
- EXPECT_EQ(10, multiuser_get_user_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_user_id(0));
+ EXPECT_EQ(0U, multiuser_get_user_id(1000));
+ EXPECT_EQ(0U, multiuser_get_user_id(10000));
+ EXPECT_EQ(0U, multiuser_get_user_id(50000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1000000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1001000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1010000));
+ EXPECT_EQ(10U, multiuser_get_user_id(1050000));
}
TEST(MultiuserTest, TestSplitApp) {
- EXPECT_EQ(0, multiuser_get_app_id(0));
- EXPECT_EQ(1000, multiuser_get_app_id(1000));
- EXPECT_EQ(10000, multiuser_get_app_id(10000));
- EXPECT_EQ(50000, multiuser_get_app_id(50000));
- EXPECT_EQ(0, multiuser_get_app_id(1000000));
- EXPECT_EQ(1000, multiuser_get_app_id(1001000));
- EXPECT_EQ(10000, multiuser_get_app_id(1010000));
- EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+ EXPECT_EQ(0U, multiuser_get_app_id(0));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(10000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(50000));
+ EXPECT_EQ(0U, multiuser_get_app_id(1000000));
+ EXPECT_EQ(1000U, multiuser_get_app_id(1001000));
+ EXPECT_EQ(10000U, multiuser_get_app_id(1010000));
+ EXPECT_EQ(50000U, multiuser_get_app_id(1050000));
}
TEST(MultiuserTest, TestCache) {
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 1000));
- EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_cache_gid(0, 50000));
- EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
+ EXPECT_EQ(20000U, multiuser_get_cache_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(1020000U, multiuser_get_cache_gid(10, 10000));
}
TEST(MultiuserTest, TestExt) {
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 1000));
- EXPECT_EQ(30000, multiuser_get_ext_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_ext_gid(0, 50000));
- EXPECT_EQ(1030000, multiuser_get_ext_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 1000));
+ EXPECT_EQ(30000U, multiuser_get_ext_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_ext_gid(0, 50000));
+ EXPECT_EQ(1030000U, multiuser_get_ext_gid(10, 10000));
}
TEST(MultiuserTest, TestShared) {
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 0));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 1000));
- EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
- EXPECT_EQ(-1, multiuser_get_shared_gid(0, 50000));
- EXPECT_EQ(1050000, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(50000U, multiuser_get_shared_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
+ EXPECT_EQ(1050000U, multiuser_get_shared_gid(10, 10000));
}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 0441fb6..b762ac1 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -101,7 +101,7 @@
// should always be able to read its port.
for (int port : {10000, 12345, 15999, 20202, 25000}) {
for (int type : {SOCK_DGRAM, SOCK_STREAM}) {
- server = socket_inaddr_any_server(port, SOCK_DGRAM);
+ server = socket_inaddr_any_server(port, type);
if (server != INVALID_SOCKET) {
EXPECT_EQ(port, socket_get_local_port(server));
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 7f852d4..d67dee5 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -67,8 +67,8 @@
std::vector<const char*> argv_hold;
std::vector<std::string> envs;
std::vector<const char*> envp_hold;
- int output_fd;
- int error_fd;
+ int output_fd; // duplication of fileno(output) (below)
+ int error_fd; // duplication of fileno(error) (below)
// library
int fds[2]; // From popen call
@@ -284,6 +284,15 @@
return;
}
context->output = fdopen(context->output_fd, "web");
+ if (context->output == NULL) {
+ logcat_panic(context, HELP_FALSE, "couldn't fdopen output file");
+ return;
+ }
+ if (context->stderr_stdout) {
+ close_error(context);
+ context->error = context->output;
+ context->error_fd = context->output_fd;
+ }
context->outByteCount = 0;
}
@@ -788,6 +797,7 @@
// Simulate shell stderr redirect parsing
if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue;
+ // Append to file not implemented, just open file
size_t skip = (argv[i][2] == '>') + 2;
if (!strcmp(&argv[i][skip], "/dev/null")) {
context->stderr_null = true;
@@ -799,16 +809,29 @@
"stderr redirection to file %s unsupported, skipping\n",
&argv[i][skip]);
}
+ // Only the first one
+ break;
+ }
+
+ const char* filename = NULL;
+ for (int i = 0; i < argc; ++i) {
+ // Simulate shell stdout redirect parsing
+ if (argv[i][0] != '>') continue;
+
+ // Append to file not implemented, just open file
+ filename = &argv[i][(argv[i][1] == '>') + 1];
+ // Only the first one
+ break;
}
// Deal with setting up file descriptors and FILE pointers
- if (context->error_fd >= 0) {
+ if (context->error_fd >= 0) { // Is an error file descriptor supplied?
if (context->error_fd == context->output_fd) {
context->stderr_stdout = true;
- } else if (context->stderr_null) {
+ } else if (context->stderr_null) { // redirection told us to close it
close(context->error_fd);
context->error_fd = -1;
- } else {
+ } else { // All Ok, convert error to a FILE pointer
context->error = fdopen(context->error_fd, "web");
if (!context->error) {
context->retval = -errno;
@@ -819,22 +842,32 @@
}
}
}
- if (context->output_fd >= 0) {
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : context->error,
- "Failed to fdopen(output_fd=%d) %s\n", context->output_fd,
- strerror(errno));
- goto exit;
+ if (context->output_fd >= 0) { // Is an output file descriptor supplied?
+ if (filename) { // redirect to file, close the supplied file descriptor.
+ close(context->output_fd);
+ context->output_fd = -1;
+ } else { // All Ok, convert output to a FILE pointer
+ context->output = fdopen(context->output_fd, "web");
+ if (!context->output) {
+ context->retval = -errno;
+ fprintf(context->stderr_stdout ? stdout : context->error,
+ "Failed to fdopen(output_fd=%d) %s\n",
+ context->output_fd, strerror(errno));
+ goto exit;
+ }
}
}
+ if (filename) { // We supplied an output file redirected in command line
+ context->output = fopen(filename, "web");
+ }
+ // Deal with 2>&1
if (context->stderr_stdout) context->error = context->output;
+ // Deal with 2>/dev/null
if (context->stderr_null) {
context->error_fd = -1;
context->error = NULL;
}
- // Only happens if output=stdout
+ // Only happens if output=stdout or output=filename
if ((context->output_fd < 0) && context->output) {
context->output_fd = fileno(context->output);
}
@@ -1351,6 +1384,8 @@
for (int i = optind ; i < argc ; i++) {
// skip stderr redirections of _all_ kinds
if ((argv[i][0] == '2') && (argv[i][1] == '>')) continue;
+ // skip stdout redirections of _all_ kinds
+ if (argv[i][0] == '>') continue;
err = android_log_addFilterString(context->logformat, argv[i]);
if (err < 0) {
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 1c3feba..22aca17 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -27,11 +27,12 @@
-fno-builtin \
# -----------------------------------------------------------------------------
-# Benchmarks (actually a gTest where the result code does not matter)
+# Benchmarks
# ----------------------------------------------------------------------------
benchmark_src_files := \
- logcat_benchmark.cpp
+ logcat_benchmark.cpp \
+ exec_benchmark.cpp \
# Build benchmarks for the device. Run with:
# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
@@ -40,7 +41,8 @@
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
LOCAL_SRC_FILES := $(benchmark_src_files)
-include $(BUILD_NATIVE_TEST)
+LOCAL_SHARED_LIBRARIES := libbase liblogcat
+include $(BUILD_NATIVE_BENCHMARK)
# -----------------------------------------------------------------------------
# Unit tests.
diff --git a/logcat/tests/exec_benchmark.cpp b/logcat/tests/exec_benchmark.cpp
new file mode 100644
index 0000000..c30a5f5
--- /dev/null
+++ b/logcat/tests/exec_benchmark.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <android-base/file.h>
+#include <benchmark/benchmark.h>
+#include <log/logcat.h>
+
+// Dump the statistics and report results
+
+static void logcat_popen_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ FILE* fp = popen(cmd, "r");
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ pclose(fp);
+ }
+}
+
+static void BM_logcat_stat_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_libc);
+
+static void logcat_popen_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_context ctx;
+ FILE* fp = android_logcat_popen(&ctx, cmd);
+ std::string ret;
+ android::base::ReadFdToString(fileno(fp), &ret);
+ android_logcat_pclose(&ctx, fp);
+ }
+}
+
+static void BM_logcat_stat_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -S");
+}
+BENCHMARK(BM_logcat_stat_popen_liblogcat);
+
+static void logcat_system_libc(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_libc);
+
+static void logcat_system_liblogcat(benchmark::State& state, const char* cmd) {
+ while (state.KeepRunning()) {
+ android_logcat_system(cmd);
+ }
+}
+
+static void BM_logcat_stat_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -S >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_stat_system_liblogcat);
+
+// Dump the logs and report results
+
+static void BM_logcat_dump_popen_libc(benchmark::State& state) {
+ logcat_popen_libc(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_libc);
+
+static void BM_logcat_dump_popen_liblogcat(benchmark::State& state) {
+ logcat_popen_liblogcat(state, "logcat -b all -d");
+}
+BENCHMARK(BM_logcat_dump_popen_liblogcat);
+
+static void BM_logcat_dump_system_libc(benchmark::State& state) {
+ logcat_system_libc(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_libc);
+
+static void BM_logcat_dump_system_liblogcat(benchmark::State& state) {
+ logcat_system_liblogcat(state, "logcat -b all -d >/dev/null 2>/dev/null");
+}
+BENCHMARK(BM_logcat_dump_system_liblogcat);
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index dd85164..8d88628 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -18,19 +18,22 @@
#include <stdlib.h>
#include <string.h>
-#include <gtest/gtest.h>
+#include <benchmark/benchmark.h>
static const char begin[] = "--------- beginning of ";
-TEST(logcat, sorted_order) {
- FILE *fp;
+static void BM_logcat_sorted_order(benchmark::State& state) {
+ FILE* fp;
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
+ if (!state.KeepRunning()) return;
+
+ fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r");
+ if (!fp) return;
class timestamp {
- private:
+ private:
int month;
int day;
int hour;
@@ -39,44 +42,39 @@
int millisecond;
bool ok;
- public:
- void init(const char *buffer)
- {
+ public:
+ void init(const char* buffer) {
ok = false;
if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
- &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
+ &minute, &second, &millisecond) == 6;
}
}
- explicit timestamp(const char *buffer)
- {
+ explicit timestamp(const char* buffer) {
init(buffer);
}
- bool operator< (timestamp &T)
- {
- return !ok || !T.ok
- || (month < T.month)
- || ((month == T.month)
- && ((day < T.day)
- || ((day == T.day)
- && ((hour < T.hour)
- || ((hour == T.hour)
- && ((minute < T.minute)
- || ((minute == T.minute)
- && ((second < T.second)
- || ((second == T.second)
- && (millisecond < T.millisecond))))))))));
+ bool operator<(timestamp& T) {
+ return !ok || !T.ok || (month < T.month) ||
+ ((month == T.month) &&
+ ((day < T.day) ||
+ ((day == T.day) &&
+ ((hour < T.hour) ||
+ ((hour == T.hour) &&
+ ((minute < T.minute) ||
+ ((minute == T.minute) &&
+ ((second < T.second) ||
+ ((second == T.second) &&
+ (millisecond < T.millisecond))))))))));
}
- bool valid(void)
- {
+ bool valid(void) {
return ok;
}
} last(NULL);
- char *last_buffer = NULL;
+ char* last_buffer = NULL;
char buffer[5120];
int count = 0;
@@ -114,15 +112,22 @@
// Allow few fails, happens with readers active
fprintf(stderr, "%s: %d/%d out of order entries\n",
- (next_lt_last)
- ? ((next_lt_last <= max_ok)
- ? "WARNING"
- : "ERROR")
- : "INFO",
+ (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
+ : "INFO",
next_lt_last, count);
- EXPECT_GE(max_ok, next_lt_last);
+ if (next_lt_last > max_ok) {
+ fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
+ next_lt_last);
+ }
// sample statistically too small
- EXPECT_LT(100, count);
+ if (count < 100) {
+ fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
+ }
+
+ state.KeepRunning();
}
+BENCHMARK(BM_logcat_sorted_order);
+
+BENCHMARK_MAIN();