From 6dabc81a0b7eac772209e8eef70ff3b156e5cc6b Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 10 Feb 2017 13:09:07 -0800 Subject: [PATCH] liblogcat: add android_logcat_popen and android_logcat_system Supply a wrapper to the logcat API that provides some analogous functionality to popen and system libc calls with some bits of KISS shell-like parsing for environment, quotes and error redirection handling. Test: gTest logcat-unit-tests Bug: 35326290 Change-Id: I9494ce71267ad2b2bec7fcccfc7d4beddae9aea6 --- logcat/Android.mk | 2 +- logcat/include/log/logcat.h | 18 +++ logcat/logcat_system.cpp | 148 ++++++++++++++++++++++++ logcat/tests/Android.mk | 4 +- logcat/tests/liblogcat_test.cpp | 25 ++++ logcat/tests/logcat_test.cpp | 195 +++++++++++++++++++------------- 6 files changed, 311 insertions(+), 81 deletions(-) create mode 100644 logcat/logcat_system.cpp create mode 100644 logcat/tests/liblogcat_test.cpp diff --git a/logcat/Android.mk b/logcat/Android.mk index 4b8746c9a..5ed0938fd 100644 --- a/logcat/Android.mk +++ b/logcat/Android.mk @@ -17,7 +17,7 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := liblogcat -LOCAL_SRC_FILES := logcat.cpp +LOCAL_SRC_FILES := logcat.cpp logcat_system.cpp LOCAL_SHARED_LIBRARIES := $(logcatLibs) LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_EXPORT_C_INCLUDES_DIR := $(LOCAL_PATH)/include diff --git a/logcat/include/log/logcat.h b/logcat/include/log/logcat.h index c41a6b7b7..009672cd5 100644 --- a/logcat/include/log/logcat.h +++ b/logcat/include/log/logcat.h @@ -17,6 +17,8 @@ #ifndef _LIBS_LOGCAT_H /* header boilerplate */ #define _LIBS_LOGCAT_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -95,6 +97,22 @@ int android_logcat_run_command_thread_running(android_logcat_context ctx); */ int android_logcat_destroy(android_logcat_context* ctx); +/* derived helpers */ + +/* + * In-process thread that acts like somewhat like libc-like system and popen + * respectively. Can not handle shell scripting, only pure calls to the + * logcat operations. The android_logcat_system is a wrapper for the + * create_android_logcat, android_logcat_run_command and android_logcat_destroy + * API above. The android_logcat_popen is a wrapper for the + * android_logcat_run_command_thread API above. The android_logcat_pclose is + * a wrapper for a reasonable wait until output has subsided for command + * completion, fclose on the FILE pointer and the android_logcat_destroy API. + */ +int android_logcat_system(const char* command); +FILE* android_logcat_popen(android_logcat_context* ctx, const char* command); +int android_logcat_pclose(android_logcat_context* ctx, FILE* output); + #endif /* __ANDROID_USE_LIBLOG_LOGCAT_INTERFACE */ #ifdef __cplusplus diff --git a/logcat/logcat_system.cpp b/logcat/logcat_system.cpp new file mode 100644 index 000000000..ea393bd67 --- /dev/null +++ b/logcat/logcat_system.cpp @@ -0,0 +1,148 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +#include + +static std::string unquote(const char*& cp, const char*& delim) { + if ((*cp == '\'') || (*cp == '"')) { + // KISS: Simple quotes. Do not handle the case + // of concatenation like "blah"foo'bar' + char quote = *cp++; + delim = strchr(cp, quote); + if (!delim) delim = cp + strlen(cp); + std::string str(cp, delim); + if (*delim) ++delim; + return str; + } + delim = strpbrk(cp, " \t\f\r\n"); + if (!delim) delim = cp + strlen(cp); + return std::string(cp, delim); +} + +static bool __android_logcat_parse(const char* command, + std::vector& args, + std::vector& envs) { + for (const char *delim, *cp = command; cp && *cp; cp = delim) { + while (isspace(*cp)) ++cp; + if ((args.size() == 0) && (*cp != '=') && !isdigit(*cp)) { + const char* env = cp; + while (isalnum(*cp) || (*cp == '_')) ++cp; + if (cp && (*cp == '=')) { + std::string str(env, ++cp); + str += unquote(cp, delim); + envs.push_back(str); + continue; + } + cp = env; + } + args.push_back(unquote(cp, delim)); + if ((args.size() == 1) && (args[0] != "logcat") && + (args[0] != "/system/bin/logcat")) { + return false; + } + } + return args.size() != 0; +} + +FILE* android_logcat_popen(android_logcat_context* ctx, const char* command) { + *ctx = NULL; + + std::vector args; + std::vector envs; + if (!__android_logcat_parse(command, args, envs)) return NULL; + + std::vector argv; + for (auto& str : args) { + argv.push_back(str.c_str()); + } + argv.push_back(NULL); + + std::vector envp; + for (auto& str : envs) { + envp.push_back(str.c_str()); + } + envp.push_back(NULL); + + *ctx = create_android_logcat(); + if (!*ctx) return NULL; + + int fd = android_logcat_run_command_thread( + *ctx, argv.size() - 1, (char* const*)&argv[0], (char* const*)&envp[0]); + argv.clear(); + args.clear(); + envp.clear(); + envs.clear(); + if (fd < 0) { + android_logcat_destroy(ctx); + return NULL; + } + + FILE* retval = fdopen(fd, "reb"); + if (!retval) android_logcat_destroy(ctx); + return retval; +} + +int android_logcat_pclose(android_logcat_context* ctx, FILE* output) { + if (*ctx) { + static const useconds_t wait_sample = 20000; + // Wait two seconds maximum + for (size_t retry = ((2 * 1000000) + wait_sample - 1) / wait_sample; + android_logcat_run_command_thread_running(*ctx) && retry; --retry) { + usleep(wait_sample); + } + } + + if (output) fclose(output); + return android_logcat_destroy(ctx); +} + +int android_logcat_system(const char* command) { + std::vector args; + std::vector envs; + if (!__android_logcat_parse(command, args, envs)) return -1; + + std::vector argv; + for (auto& str : args) { + argv.push_back(str.c_str()); + } + argv.push_back(NULL); + + std::vector envp; + for (auto& str : envs) { + envp.push_back(str.c_str()); + } + envp.push_back(NULL); + + android_logcat_context ctx = create_android_logcat(); + if (!ctx) return -1; + /* Command return value */ + int retval = android_logcat_run_command(ctx, -1, -1, argv.size() - 1, + (char* const*)&argv[0], + (char* const*)&envp[0]); + /* destroy return value */ + int ret = android_logcat_destroy(&ctx); + /* Paranoia merging any discrepancies between the two return values */ + if (!ret) ret = retval; + return ret; +} diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk index cb8b061ed..bfb20f039 100644 --- a/logcat/tests/Android.mk +++ b/logcat/tests/Android.mk @@ -48,6 +48,7 @@ include $(BUILD_NATIVE_TEST) test_src_files := \ logcat_test.cpp \ + liblogcat_test.cpp \ # Build tests for the device (with .so). Run with: # adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests @@ -55,6 +56,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) LOCAL_CFLAGS += $(test_c_flags) -LOCAL_SHARED_LIBRARIES := liblog libbase +LOCAL_SHARED_LIBRARIES := liblog libbase liblogcat +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include LOCAL_SRC_FILES := $(test_src_files) include $(BUILD_NATIVE_TEST) diff --git a/logcat/tests/liblogcat_test.cpp b/logcat/tests/liblogcat_test.cpp new file mode 100644 index 000000000..9e9a2c25f --- /dev/null +++ b/logcat/tests/liblogcat_test.cpp @@ -0,0 +1,25 @@ +/* + * 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 + +#define logcat_define(context) android_logcat_context context +#define logcat_popen(context, command) android_logcat_popen(&context, command) +#define logcat_pclose(context, fp) android_logcat_pclose(&context, fp) +#define logcat_system(command) android_logcat_system(command) +#define logcat liblogcat + +#include "logcat_test.cpp" diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp index 8f2da2109..9c777b3a9 100644 --- a/logcat/tests/logcat_test.cpp +++ b/logcat/tests/logcat_test.cpp @@ -33,6 +33,13 @@ #include #include +#ifndef logcat_popen +#define logcat_define(context) +#define logcat_popen(context, command) popen((command), "r") +#define logcat_pclose(context, fp) pclose(fp) +#define logcat_system(command) system(command) +#endif + #define BIG_BUFFER (5 * 1024) // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and @@ -53,6 +60,7 @@ static const char begin[] = "--------- beginning of "; TEST(logcat, buckets) { FILE* fp; + logcat_define(ctx); #undef LOG_TAG #define LOG_TAG "inject" @@ -61,9 +69,9 @@ TEST(logcat, buckets) { ASSERT_TRUE( NULL != - (fp = - popen("logcat -b radio -b events -b system -b main -d 2>/dev/null", - "r"))); + (fp = logcat_popen( + ctx, + "logcat -b radio -b events -b system -b main -d 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -81,7 +89,7 @@ TEST(logcat, buckets) { } } - pclose(fp); + logcat_pclose(ctx, fp); EXPECT_EQ(15, ids); @@ -90,11 +98,13 @@ TEST(logcat, buckets) { TEST(logcat, event_tag_filter) { FILE* fp; + logcat_define(ctx); - ASSERT_TRUE(NULL != (fp = popen("logcat -b events -d -s auditd " - "am_proc_start am_pss am_proc_bound " - "dvm_lock_sample am_wtf 2>/dev/null", - "r"))); + ASSERT_TRUE(NULL != + (fp = logcat_popen(ctx, + "logcat -b events -d -s auditd " + "am_proc_start am_pss am_proc_bound " + "dvm_lock_sample am_wtf 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -104,7 +114,7 @@ TEST(logcat, event_tag_filter) { ++count; } - pclose(fp); + logcat_pclose(ctx, fp); EXPECT_LT(4, count); } @@ -146,6 +156,7 @@ TEST(logcat, year) { do { FILE* fp; + logcat_define(ctx); char needle[32]; time_t now; @@ -161,7 +172,8 @@ TEST(logcat, year) { ASSERT_TRUE( NULL != - (fp = popen("logcat -v long -v year -b all -t 3 2>/dev/null", "r"))); + (fp = logcat_popen( + ctx, "logcat -v long -v year -b all -t 3 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -172,7 +184,7 @@ TEST(logcat, year) { ++count; } } - pclose(fp); + logcat_pclose(ctx, fp); } while ((count < 3) && --tries && inject(3 - count)); @@ -222,10 +234,12 @@ TEST(logcat, tz) { do { FILE* fp; + logcat_define(ctx); - ASSERT_TRUE(NULL != (fp = popen("logcat -v long -v America/Los_Angeles " - "-b all -t 3 2>/dev/null", - "r"))); + ASSERT_TRUE(NULL != + (fp = logcat_popen(ctx, + "logcat -v long -v America/Los_Angeles " + "-b all -t 3 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -239,7 +253,7 @@ TEST(logcat, tz) { } } - pclose(fp); + logcat_pclose(ctx, fp); } while ((count < 3) && --tries && inject(3 - count)); @@ -248,10 +262,12 @@ TEST(logcat, tz) { TEST(logcat, ntz) { FILE* fp; + logcat_define(ctx); - ASSERT_TRUE(NULL != (fp = popen("logcat -v long -v America/Los_Angeles -v " - "zone -b all -t 3 2>/dev/null", - "r"))); + ASSERT_TRUE(NULL != + (fp = logcat_popen(ctx, + "logcat -v long -v America/Los_Angeles -v " + "zone -b all -t 3 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -263,7 +279,7 @@ TEST(logcat, ntz) { } } - pclose(fp); + logcat_pclose(ctx, fp); ASSERT_EQ(0, count); } @@ -281,7 +297,8 @@ static void do_tail(int num) { "ANDROID_PRINTF_LOG=long logcat -b all -t %d 2>/dev/null", num); FILE* fp; - ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); + logcat_define(ctx); + ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); count = 0; @@ -289,7 +306,7 @@ static void do_tail(int num) { ++count; } - pclose(fp); + logcat_pclose(ctx, fp); } while ((count < num) && --tries && inject(num - count)); @@ -326,13 +343,14 @@ TEST(logcat, tail_time) { int tries = 4; // in case run too soon after system start or buffer clear do { - ASSERT_TRUE(NULL != (fp = popen("logcat" - " -v long" - " -v nsec" - " -b all" - " -t 10" - " 2>&1", - "r"))); + logcat_define(ctx); + ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, + "logcat" + " -v long" + " -v nsec" + " -b all" + " -t 10" + " 2>&1"))); count = 0; while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) { @@ -345,7 +363,7 @@ TEST(logcat, tail_time) { free(last_timestamp); last_timestamp = strdup(input); } - pclose(fp); + logcat_pclose(ctx, fp); } while ((count < 10) && --tries && inject(10 - count)); @@ -362,7 +380,8 @@ TEST(logcat, tail_time) { " -t '%s'" " 2>&1", first_timestamp); - ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); + logcat_define(ctx); + ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); int second_count = 0; int last_timestamp_count = -1; @@ -402,7 +421,7 @@ TEST(logcat, tail_time) { last_timestamp_count = second_count; } } - pclose(fp); + logcat_pclose(ctx, fp); EXPECT_TRUE(found); if (!found) { @@ -435,9 +454,10 @@ TEST(logcat, End_to_End) { ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); FILE* fp; - ASSERT_TRUE( - NULL != - (fp = popen("logcat -v brief -b events -t 100 2>/dev/null", "r"))); + logcat_define(ctx); + ASSERT_TRUE(NULL != + (fp = logcat_popen( + ctx, "logcat -v brief -b events -t 100 2>/dev/null"))); char buffer[BIG_BUFFER]; @@ -458,16 +478,17 @@ TEST(logcat, End_to_End) { } } - pclose(fp); + logcat_pclose(ctx, fp); ASSERT_EQ(1, count); } static int get_groups(const char* cmd) { FILE* fp; + logcat_define(ctx); // NB: crash log only available in user space - EXPECT_TRUE(NULL != (fp = popen(cmd, "r"))); + EXPECT_TRUE(NULL != (fp = logcat_popen(ctx, cmd))); if (fp == NULL) { return 0; @@ -531,7 +552,7 @@ static int get_groups(const char* cmd) { } } - pclose(fp); + logcat_pclose(ctx, fp); return count; } @@ -555,6 +576,7 @@ TEST(logcat, bad_buffer) { "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null")); } +#ifndef logcat static void caught_blocking(int signum) { unsigned long long v = 0xDEADBEEFA55A0000ULL; @@ -692,6 +714,7 @@ TEST(logcat, blocking_tail) { EXPECT_EQ(1, signals); } +#endif // meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message static testing::AssertionResult IsFalse(int ret, const char* command) { @@ -712,7 +735,7 @@ TEST(logcat, logrotate) { snprintf(command, sizeof(command), comm, buf); int ret; - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (!ret) { snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf); @@ -758,7 +781,7 @@ TEST(logcat, logrotate_suffix) { snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir); int ret; - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (!ret) { snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir); @@ -817,7 +840,7 @@ TEST(logcat, logrotate_continue) { snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); int ret; - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (ret) { snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(IsFalse(system(command), command)); @@ -866,7 +889,7 @@ TEST(logcat, logrotate_continue) { // re-run the command, it should only add a few lines more content if it // continues where it left off. snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (ret) { snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(IsFalse(system(command), command)); @@ -948,7 +971,7 @@ TEST(logcat, logrotate_clear) { tmp_out_dir, log_filename, num_val); int ret; - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (ret) { snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(IsFalse(system(command), command)); @@ -978,7 +1001,7 @@ TEST(logcat, logrotate_clear) { strcat(command, clear_cmd); int ret; - EXPECT_FALSE(IsFalse(ret = system(command), command)); + EXPECT_FALSE(IsFalse(ret = logcat_system(command), command)); if (ret) { snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir); EXPECT_FALSE(system(command)); @@ -1016,7 +1039,7 @@ static int logrotate_count_id(const char* logcat_cmd, const char* tmp_out_dir) { snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename); - int ret = system(command); + int ret = logcat_system(command); if (ret) { fprintf(stderr, "system(\"%s\")=%d", command, ret); return -1; @@ -1090,9 +1113,10 @@ TEST(logcat, logrotate_nodir) { "logcat -b all -d" " -f /das/nein/gerfingerpoken/logcat/log.txt" " -n 256 -r 1024"; - EXPECT_FALSE(IsFalse(0 == system(command), command)); + EXPECT_FALSE(IsFalse(0 == logcat_system(command), command)); } +#ifndef logcat static void caught_blocking_clear(int signum) { unsigned long long v = 0xDEADBEEFA55C0000ULL; @@ -1216,11 +1240,13 @@ TEST(logcat, blocking_clear) { EXPECT_EQ(1, signals); } +#endif static bool get_white_black(char** list) { FILE* fp; + logcat_define(ctx); - fp = popen("logcat -p 2>/dev/null", "r"); + fp = logcat_popen(ctx, "logcat -p 2>/dev/null"); if (fp == NULL) { fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n"); return false; @@ -1248,17 +1274,18 @@ static bool get_white_black(char** list) { asprintf(list, "%s", buf); } } - pclose(fp); + logcat_pclose(ctx, fp); return *list != NULL; } static bool set_white_black(const char* list) { FILE* fp; + logcat_define(ctx); char buffer[BIG_BUFFER]; snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : ""); - fp = popen(buffer, "r"); + fp = logcat_popen(ctx, buffer); if (fp == NULL) { fprintf(stderr, "ERROR: %s\n", buffer); return false; @@ -1277,10 +1304,10 @@ static bool set_white_black(const char* list) { continue; } fprintf(stderr, "%s\n", buf); - pclose(fp); + logcat_pclose(ctx, fp); return false; } - return pclose(fp) == 0; + return logcat_pclose(ctx, fp) == 0; } TEST(logcat, white_black_adjust) { @@ -1315,44 +1342,51 @@ TEST(logcat, white_black_adjust) { TEST(logcat, regex) { FILE* fp; + logcat_define(ctx); int count = 0; char buffer[BIG_BUFFER]; +// Have to make liblogcat data unique from logcat data injection +#ifdef logcat +#define logcat_regex_prefix "lolcat_test" +#else +#define logcat_regex_prefix "logcat_test" +#endif - snprintf(buffer, sizeof(buffer), "logcat --pid %d -d -e logcat_test_a+b", - getpid()); - - LOG_FAILURE_RETRY( - __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_ab")); - LOG_FAILURE_RETRY( - __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test_b")); - LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", - "logcat_test_aaaab")); - LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", - "logcat_test_aaaa")); + snprintf(buffer, sizeof(buffer), + "logcat --pid %d -d -e " logcat_regex_prefix "_a+b", getpid()); + LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, + logcat_regex_prefix "_ab")); + LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, + logcat_regex_prefix "_b")); + LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, + logcat_regex_prefix "_aaaab")); + LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix, + logcat_regex_prefix "_aaaa")); // Let the logs settle sleep(1); - ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); + ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); while (fgets(buffer, sizeof(buffer), fp)) { if (!strncmp(begin, buffer, sizeof(begin) - 1)) { continue; } - EXPECT_TRUE(strstr(buffer, "logcat_test_") != NULL); + EXPECT_TRUE(strstr(buffer, logcat_regex_prefix "_") != NULL); count++; } - pclose(fp); + logcat_pclose(ctx, fp); ASSERT_EQ(2, count); } TEST(logcat, maxcount) { FILE* fp; + logcat_define(ctx); int count = 0; char buffer[BIG_BUFFER]; @@ -1372,7 +1406,7 @@ TEST(logcat, maxcount) { // Let the logs settle sleep(1); - ASSERT_TRUE(NULL != (fp = popen(buffer, "r"))); + ASSERT_TRUE(NULL != (fp = logcat_popen(ctx, buffer))); while (fgets(buffer, sizeof(buffer), fp)) { if (!strncmp(begin, buffer, sizeof(begin) - 1)) { @@ -1382,7 +1416,7 @@ TEST(logcat, maxcount) { count++; } - pclose(fp); + logcat_pclose(ctx, fp); ASSERT_EQ(3, count); } @@ -1394,14 +1428,14 @@ static bool End_to_End(const char* tag, const char* fmt, ...) ; static bool End_to_End(const char* tag, const char* fmt, ...) { - FILE* fp = popen( - "logcat" - " -v brief" - " -b events" - " -v descriptive" - " -t 100" - " 2>/dev/null", - "r"); + logcat_define(ctx); + FILE* fp = logcat_popen(ctx, + "logcat" + " -v brief" + " -b events" + " -v descriptive" + " -t 100" + " 2>/dev/null"); if (!fp) { fprintf(stderr, "End_to_End: popen failed"); return false; @@ -1436,17 +1470,19 @@ static bool End_to_End(const char* tag, const char* fmt, ...) { } } - pclose(fp); + logcat_pclose(ctx, fp); if ((count == 0) && (lastMatch.length() > 0)) { // Help us pinpoint where things went wrong ... fprintf(stderr, "Closest match for\n %s\n is\n %s", expect.c_str(), lastMatch.c_str()); - } else if (count > 1) { + } else if (count > 2) { fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str()); } - return count == 1; + // Expect one the first time around as either liblogcat.descriptive or + // logcat.descriptive. Expect two the second time as the other. + return count == 1 || count == 2; } TEST(logcat, descriptive) { @@ -1568,12 +1604,13 @@ TEST(logcat, descriptive) { } static bool reportedSecurity(const char* command) { - FILE* fp = popen(command, "r"); + logcat_define(ctx); + FILE* fp = logcat_popen(ctx, command); if (!fp) return true; std::string ret; bool val = android::base::ReadFdToString(fileno(fp), &ret); - pclose(fp); + logcat_pclose(ctx, fp); if (!val) return true; return std::string::npos != ret.find("'security'");