Merge "Address const issue in preparation for libcxx rebase."
diff --git a/base/include/android-base/errors.h b/base/include/android-base/errors.h
index ca621fa..04c299c 100644
--- a/base/include/android-base/errors.h
+++ b/base/include/android-base/errors.h
@@ -27,8 +27,8 @@
// special handling to get the error string. Refer to Microsoft documentation
// to determine which error code to check for each function.
-#ifndef BASE_ERRORS_H
-#define BASE_ERRORS_H
+#ifndef ANDROID_BASE_ERRORS_H
+#define ANDROID_BASE_ERRORS_H
#include <string>
@@ -43,4 +43,4 @@
} // namespace base
} // namespace android
-#endif // BASE_ERRORS_H
+#endif // ANDROID_BASE_ERRORS_H
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 5342d98..aa18ea7 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_FILE_H
-#define BASE_FILE_H
+#ifndef ANDROID_BASE_FILE_H
+#define ANDROID_BASE_FILE_H
#include <sys/stat.h>
#include <string>
@@ -46,4 +46,4 @@
} // namespace base
} // namespace android
-#endif // BASE_FILE_H
+#endif // ANDROID_BASE_FILE_H
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 41fe4b3..b86c232 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef BASE_LOGGING_H
-#define BASE_LOGGING_H
+
+#ifndef ANDROID_BASE_LOGGING_H
+#define ANDROID_BASE_LOGGING_H
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
@@ -346,4 +347,4 @@
} // namespace base
} // namespace android
-#endif // BASE_LOGGING_H
+#endif // ANDROID_BASE_LOGGING_H
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index b1ce7c6..913a9a0 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef UTILS_MACROS_H
-#define UTILS_MACROS_H
+#ifndef ANDROID_BASE_MACROS_H
+#define ANDROID_BASE_MACROS_H
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
@@ -185,4 +185,4 @@
} while (0)
#endif
-#endif // UTILS_MACROS_H
+#endif // ANDROID_BASE_MACROS_H
diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h
index 882582f..3a2f8fa 100644
--- a/base/include/android-base/memory.h
+++ b/base/include/android-base/memory.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_MEMORY_H
-#define BASE_MEMORY_H
+#ifndef ANDROID_BASE_MEMORY_H
+#define ANDROID_BASE_MEMORY_H
namespace android {
namespace base {
@@ -44,4 +44,4 @@
} // namespace base
} // namespace android
-#endif // BASE_MEMORY_H
+#endif // ANDROID_BASE_MEMORY_H
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index 0543795..ed75e2d 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_PARSEINT_H
-#define BASE_PARSEINT_H
+#ifndef ANDROID_BASE_PARSEINT_H
+#define ANDROID_BASE_PARSEINT_H
#include <errno.h>
#include <stdlib.h>
@@ -70,4 +70,4 @@
} // namespace base
} // namespace android
-#endif // BASE_PARSEINT_H
+#endif // ANDROID_BASE_PARSEINT_H
diff --git a/base/include/android-base/parsenetaddress.h b/base/include/android-base/parsenetaddress.h
index 2de5ac9..b4ac025 100644
--- a/base/include/android-base/parsenetaddress.h
+++ b/base/include/android-base/parsenetaddress.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_PARSENETADDRESS_H
-#define BASE_PARSENETADDRESS_H
+#ifndef ANDROID_BASE_PARSENETADDRESS_H
+#define ANDROID_BASE_PARSENETADDRESS_H
#include <string>
@@ -35,4 +35,4 @@
} // namespace base
} // namespace android
-#endif // BASE_PARSENETADDRESS_H
+#endif // ANDROID_BASE_PARSENETADDRESS_H
diff --git a/base/include/android-base/stringprintf.h b/base/include/android-base/stringprintf.h
index d68af87..cf666ab 100644
--- a/base/include/android-base/stringprintf.h
+++ b/base/include/android-base/stringprintf.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_STRINGPRINTF_H
-#define BASE_STRINGPRINTF_H
+#ifndef ANDROID_BASE_STRINGPRINTF_H
+#define ANDROID_BASE_STRINGPRINTF_H
#include <stdarg.h>
#include <string>
@@ -53,4 +53,4 @@
} // namespace base
} // namespace android
-#endif // BASE_STRINGPRINTF_H
+#endif // ANDROID_BASE_STRINGPRINTF_H
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 20da144..69781cd 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_STRINGS_H
-#define BASE_STRINGS_H
+#ifndef ANDROID_BASE_STRINGS_H
+#define ANDROID_BASE_STRINGS_H
#include <sstream>
#include <string>
@@ -65,4 +65,4 @@
} // namespace base
} // namespace android
-#endif // BASE_STRINGS_H
+#endif // ANDROID_BASE_STRINGS_H
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 3f6872c..4ea3c8e 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef TEST_UTILS_H
-#define TEST_UTILS_H
+#ifndef ANDROID_BASE_TEST_UTILS_H
+#define ANDROID_BASE_TEST_UTILS_H
#include <string>
@@ -48,4 +48,4 @@
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};
-#endif // TEST_UTILS_H
+#endif // ANDROID_BASE_TEST_UTILS_H
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index 90979df..2422102 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef UTILS_THREAD_ANNOTATIONS_H
-#define UTILS_THREAD_ANNOTATIONS_H
+#ifndef ANDROID_BASE_THREAD_ANNOTATIONS_H
+#define ANDROID_BASE_THREAD_ANNOTATIONS_H
#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
@@ -80,4 +80,4 @@
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
-#endif // UTILS_THREAD_ANNOTATIONS_H
+#endif // ANDROID_BASE_THREAD_ANNOTATIONS_H
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index d3b27ca..8bc49ce 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -21,18 +21,18 @@
#include <android-base/macros.h>
-/* Container for a file descriptor that automatically closes the descriptor as
- * it goes out of scope.
- *
- * unique_fd ufd(open("/some/path", "r"));
- *
- * if (ufd.get() < 0) // invalid descriptor
- * return error;
- *
- * // Do something useful
- *
- * return 0; // descriptor is closed here
- */
+// Container for a file descriptor that automatically closes the descriptor as
+// it goes out of scope.
+//
+// unique_fd ufd(open("/some/path", "r"));
+// if (ufd.get() == -1) return error;
+//
+// // Do something useful, possibly including 'return'.
+//
+// return 0; // Descriptor is closed for you.
+//
+// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
+// you find this class if you're searching for one of those names.
namespace android {
namespace base {
@@ -44,14 +44,18 @@
~unique_fd() { clear(); }
unique_fd(unique_fd&& other) : value_(other.release()) {}
- unique_fd& operator = (unique_fd&& s) {
+ unique_fd& operator=(unique_fd&& s) {
reset(s.release());
return *this;
}
void reset(int new_value) {
- if (value_ >= 0)
+ if (value_ != -1) {
+ // Even if close(2) fails with EINTR, the fd will have been closed.
+ // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
+ // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
close(value_);
+ }
value_ = new_value;
}
@@ -60,8 +64,9 @@
}
int get() const { return value_; }
+ operator int() const { return get(); }
- int release() {
+ int release() __attribute__((warn_unused_result)) {
int ret = value_;
value_ = -1;
return ret;
@@ -76,4 +81,4 @@
} // namespace base
} // namespace android
-#endif // ANDROID_BASE_UNIQUE_FD_H
+#endif // ANDROID_BASE_UNIQUE_FD_H
diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h
index 3b0ed0a..2d5a6f6 100755
--- a/base/include/android-base/utf8.h
+++ b/base/include/android-base/utf8.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BASE_UTF8_H
-#define BASE_UTF8_H
+#ifndef ANDROID_BASE_UTF8_H
+#define ANDROID_BASE_UTF8_H
#ifdef _WIN32
#include <string>
@@ -84,4 +84,4 @@
} // namespace base
} // namespace android
-#endif // BASE_UTF8_H
+#endif // ANDROID_BASE_UTF8_H
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index 5d1fae9..ef4f68e 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -55,8 +55,11 @@
return false;
}
- int32_t value = std::stoi(content);
- bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
+ // Ignore existing bootstat records (which do not contain file content).
+ if (!content.empty()) {
+ int32_t value = std::stoi(content);
+ bootstat::LogHistogram("bootstat_mtime_matches_content", value == *uptime);
+ }
return true;
}
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h
index 4d5deee..a2b8318 100644
--- a/bootstat/boot_event_record_store.h
+++ b/bootstat/boot_event_record_store.h
@@ -55,6 +55,7 @@
FRIEND_TEST(BootEventRecordStoreTest, AddMultipleBootEvents);
FRIEND_TEST(BootEventRecordStoreTest, AddBootEventWithValue);
FRIEND_TEST(BootEventRecordStoreTest, GetBootEvent);
+ FRIEND_TEST(BootEventRecordStoreTest, GetBootEventNoFileContent);
// Sets the filesystem path of the record store.
void SetStorePath(const std::string& path);
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 343f9d0..01c2cc1 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -17,12 +17,16 @@
#include "boot_event_record_store.h"
#include <dirent.h>
+#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <unistd.h>
#include <cstdint>
#include <cstdlib>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/test_utils.h>
+#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "uptime_parser.h"
@@ -31,6 +35,36 @@
namespace {
+// Creates a fake boot event record file at |record_path| containing the boot
+// record |value|. This method is necessary as truncating a
+// BootEventRecordStore-created file would modify the mtime, which would alter
+// the value of the record.
+bool CreateEmptyBootEventRecord(const std::string& record_path, int32_t value) {
+ android::base::unique_fd record_fd(creat(record_path.c_str(), S_IRUSR | S_IWUSR));
+ if (record_fd == -1) {
+ return false;
+ }
+
+ // Writing the value as content in the record file is a debug measure to
+ // ensure the validity of the file mtime value, i.e., to check that the record
+ // file mtime values are not changed once set.
+ // TODO(jhawkins): Remove this block.
+ if (!android::base::WriteStringToFd(std::to_string(value), record_fd)) {
+ return false;
+ }
+
+ // Set the |mtime| of the file to store the value of the boot event while
+ // preserving the |atime|.
+ struct timeval atime = {/* tv_sec */ 0, /* tv_usec */ 0};
+ struct timeval mtime = {/* tv_sec */ value, /* tv_usec */ 0};
+ const struct timeval times[] = {atime, mtime};
+ if (utimes(record_path.c_str(), times) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
// Returns true if the time difference between |a| and |b| is no larger
// than 10 seconds. This allow for a relatively large fuzz when comparing
// two timestamps taken back-to-back.
@@ -178,4 +212,19 @@
// Null |record|.
EXPECT_DEATH(store.GetBootEvent("carboniferous", nullptr), std::string());
-}
\ No newline at end of file
+}
+
+// Tests that the BootEventRecordStore is capable of handling an older record
+// protocol which does not contain file contents.
+TEST_F(BootEventRecordStoreTest, GetBootEventNoFileContent) {
+ BootEventRecordStore store;
+ store.SetStorePath(GetStorePathForTesting());
+
+ EXPECT_TRUE(CreateEmptyBootEventRecord(store.GetBootEventPath("devonian"), 2718));
+
+ BootEventRecordStore::BootEventRecord record;
+ bool result = store.GetBootEvent("devonian", &record);
+ EXPECT_EQ(true, result);
+ EXPECT_EQ("devonian", record.first);
+ EXPECT_EQ(2718, record.second);
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2639d05..b819797 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -224,13 +224,23 @@
time_t current_time_utc = time(nullptr);
- static const char* factory_reset_current_time = "factory_reset_current_time";
if (current_time_utc < 0) {
// UMA does not display negative values in buckets, so convert to positive.
- bootstat::LogHistogram(factory_reset_current_time, std::abs(current_time_utc));
+ bootstat::LogHistogram(
+ "factory_reset_current_time_failure", std::abs(current_time_utc));
+
+ // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // is losing records somehow.
+ boot_event_store.AddBootEventWithValue(
+ "factory_reset_current_time_failure", std::abs(current_time_utc));
return;
} else {
- bootstat::LogHistogram(factory_reset_current_time, current_time_utc);
+ bootstat::LogHistogram("factory_reset_current_time", current_time_utc);
+
+ // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // is losing records somehow.
+ boot_event_store.AddBootEventWithValue(
+ "factory_reset_current_time", current_time_utc);
}
// The factory_reset boot event does not exist after the device is reset, so
@@ -247,6 +257,12 @@
// factory_reset time.
time_t factory_reset_utc = record.second;
bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
+
+ // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+ // is losing records somehow.
+ boot_event_store.AddBootEventWithValue(
+ "factory_reset_record_value", factory_reset_utc);
+
time_t time_since_factory_reset = difftime(current_time_utc,
factory_reset_utc);
boot_event_store.AddBootEventWithValue("time_since_factory_reset",
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7e60a72..fa8f19a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -355,8 +355,8 @@
" formatting.\n"
" -s <specific device> Specify a device. For USB, provide either\n"
" a serial number or path to device port.\n"
- " For ethernet, provide an address in the"
- " form <protocol>:<hostname>[:port] where"
+ " For ethernet, provide an address in the\n"
+ " form <protocol>:<hostname>[:port] where\n"
" <protocol> is either tcp or udp.\n"
" -p <product> Specify product name.\n"
" -c <cmdline> Override kernel commandline.\n"
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 35f1a9e..6469ec4 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -27,6 +27,7 @@
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -61,19 +62,20 @@
#define UNMOUNT_CHECK_MS 5000
#define UNMOUNT_CHECK_TIMES 10
-// System call provided by bionic but not in any header file.
-extern "C" int init_module(void *, unsigned long, const char *);
-
static const int kTerminateServiceDelayMicroSeconds = 50000;
static int insmod(const char *filename, const char *options) {
- std::string module;
- if (!read_file(filename, &module)) {
+ int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
return -1;
}
-
- // TODO: use finit_module for >= 3.8 kernels.
- return init_module(&module[0], module.size(), options);
+ int rc = syscall(__NR_finit_module, fd, options, 0);
+ if (rc == -1) {
+ ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno));
+ }
+ close(fd);
+ return rc;
}
static int __ifupdown(const char *interface, int up) {
diff --git a/init/devices.cpp b/init/devices.cpp
index 557a6ac..e74140b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -413,7 +413,7 @@
static char **get_character_device_symlinks(struct uevent *uevent)
{
const char *parent;
- char *slash;
+ const char *slash;
char **links;
int link_num = 0;
int width;
@@ -467,7 +467,7 @@
{
const char *device;
struct platform_node *pdev;
- char *slash;
+ const char *slash;
const char *type;
char buf[256];
char link_path[256];
diff --git a/init/init.cpp b/init/init.cpp
index 69f0595..9b7d108 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,7 +18,6 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <fstream>
#include <libgen.h>
#include <paths.h>
#include <signal.h>
@@ -290,100 +289,6 @@
return result;
}
-static void security_failure() {
- ERROR("Security failure; rebooting into recovery mode...\n");
- android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- while (true) { pause(); } // never reached
-}
-
-#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
-#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
-
-/* __attribute__((unused)) due to lack of mips support: see mips block
- * in set_mmap_rnd_bits_action */
-static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
- std::string path;
- if (compat) {
- path = MMAP_RND_COMPAT_PATH;
- } else {
- path = MMAP_RND_PATH;
- }
- std::ifstream inf(path, std::fstream::in);
- if (!inf) {
- return false;
- }
- while (start >= min) {
- // try to write out new value
- std::string str_val = std::to_string(start);
- std::ofstream of(path, std::fstream::out);
- if (!of) {
- return false;
- }
- of << str_val << std::endl;
- of.close();
-
- // check to make sure it was recorded
- inf.seekg(0);
- std::string str_rec;
- inf >> str_rec;
- if (str_val.compare(str_rec) == 0) {
- break;
- }
- start--;
- }
- inf.close();
- return (start >= min);
-}
-
-/*
- * Set /proc/sys/vm/mmap_rnd_bits and potentially
- * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
- * Returns -1 if unable to set these to an acceptable value. Apply
- * upstream patch-sets https://lkml.org/lkml/2015/12/21/337 and
- * https://lkml.org/lkml/2016/2/4/831 to enable this.
- */
-static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
-{
- int ret = -1;
-
- /* values are arch-dependent */
-#if defined(__aarch64__)
- /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
- if (set_mmap_rnd_bits_min(33, 24, false)
- && set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
- }
-#elif defined(__x86_64__)
- /* x86_64 supports 28 - 32 bits */
- if (set_mmap_rnd_bits_min(32, 32, false)
- && set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
- }
-#elif defined(__arm__) || defined(__i386__)
- /* check to see if we're running on 64-bit kernel */
- bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
- /* supported 32-bit architecture must have 16 bits set */
- if (set_mmap_rnd_bits_min(16, 16, h64)) {
- ret = 0;
- }
-#elif defined(__mips__) || defined(__mips64__)
- // TODO: add mips support b/27788820
- ret = 0;
-#else
- ERROR("Unknown architecture\n");
-#endif
-
-#ifdef __BRILLO__
- // TODO: b/27794137
- ret = 0;
-#endif
- if (ret == -1) {
- ERROR("Unable to set adequate mmap entropy value!\n");
- security_failure();
- }
- return ret;
-}
-
static int keychord_init_action(const std::vector<std::string>& args)
{
keychord_init();
@@ -540,6 +445,12 @@
return 0;
}
+static void security_failure() {
+ ERROR("Security failure; rebooting into recovery mode...\n");
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (true) { pause(); } // never reached
+}
+
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -689,7 +600,6 @@
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
diff --git a/init/util.cpp b/init/util.cpp
index bddc3b2..4d36dfd 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -355,7 +355,7 @@
{
int ret;
char buf[256];
- char *slash;
+ const char *slash;
int width;
slash = strrchr(newpath, '/');
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 397dfda..a8a7c4a 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -94,18 +94,34 @@
libbacktrace_offline_src_files := \
BacktraceOffline.cpp \
+# Use shared llvm library on device to save space.
libbacktrace_offline_shared_libraries := \
libbacktrace \
+ libbase \
liblog \
libunwind \
-
-# Use shared llvm library on device to save space.
-libbacktrace_offline_shared_libraries_target := \
+ libutils \
libLLVM \
+libbacktrace_offline_static_libraries := \
+ libziparchive \
+ libz \
+
+module := libbacktrace_offline
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+
+libbacktrace_offline_shared_libraries := \
+ libbacktrace \
+ libbase \
+ liblog \
+ libunwind \
+ libziparchive-host \
+
# Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
# which is not included in the prebuilt.
-libbacktrace_offline_static_libraries_host := \
+libbacktrace_offline_static_libraries := \
libLLVMObject \
libLLVMBitReader \
libLLVMMC \
@@ -114,9 +130,6 @@
libLLVMSupport \
module := libbacktrace_offline
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
build_type := host
libbacktrace_multilib := both
include $(LOCAL_PATH)/Android.build.mk
@@ -129,6 +142,8 @@
liblog \
libunwind \
liblzma \
+ libziparchive \
+ libz \
libLLVMObject \
libLLVMBitReader \
libLLVMMC \
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index dc3ed67..9a4f622 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -29,11 +29,14 @@
#include <ucontext.h>
#include <unistd.h>
+#include <memory>
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include <ziparchive/zip_archive.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
@@ -641,15 +644,103 @@
return memcmp(buf, elf_magic, 4) == 0;
}
+static bool IsValidApkPath(const std::string& apk_path) {
+ static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
+ struct stat st;
+ if (stat(apk_path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
+ return false;
+ }
+ FILE* fp = fopen(apk_path.c_str(), "reb");
+ if (fp == nullptr) {
+ return false;
+ }
+ char buf[4];
+ if (fread(buf, 4, 1, fp) != 1) {
+ fclose(fp);
+ return false;
+ }
+ fclose(fp);
+ return memcmp(buf, zip_preamble, 4) == 0;
+}
+
+class ScopedZiparchiveHandle {
+ public:
+ ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
+ }
+
+ ~ScopedZiparchiveHandle() {
+ CloseArchive(handle_);
+ }
+
+ private:
+ ZipArchiveHandle handle_;
+};
+
+llvm::object::OwningBinary<llvm::object::Binary> OpenEmbeddedElfFile(const std::string& filename) {
+ llvm::object::OwningBinary<llvm::object::Binary> nothing;
+ size_t pos = filename.find("!/");
+ if (pos == std::string::npos) {
+ return nothing;
+ }
+ std::string apk_file = filename.substr(0, pos);
+ std::string elf_file = filename.substr(pos + 2);
+ if (!IsValidApkPath(apk_file)) {
+ BACK_LOGW("%s is not a valid apk file", apk_file.c_str());
+ return nothing;
+ }
+ ZipArchiveHandle handle;
+ int32_t ret_code = OpenArchive(apk_file.c_str(), &handle);
+ if (ret_code != 0) {
+ CloseArchive(handle);
+ BACK_LOGW("failed to open archive %s: %s", apk_file.c_str(), ErrorCodeString(ret_code));
+ return nothing;
+ }
+ ScopedZiparchiveHandle scoped_handle(handle);
+ ZipEntry zentry;
+ ret_code = FindEntry(handle, ZipString(elf_file.c_str()), &zentry);
+ if (ret_code != 0) {
+ BACK_LOGW("failed to find %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+ ErrorCodeString(ret_code));
+ return nothing;
+ }
+ if (zentry.method != kCompressStored || zentry.compressed_length != zentry.uncompressed_length) {
+ BACK_LOGW("%s is compressed in %s, which doesn't support running directly", elf_file.c_str(),
+ apk_file.c_str());
+ return nothing;
+ }
+ auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(GetFileDescriptor(handle), apk_file,
+ zentry.uncompressed_length,
+ zentry.offset);
+ if (!buffer_or_err) {
+ BACK_LOGW("failed to read %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+ buffer_or_err.getError().message().c_str());
+ return nothing;
+ }
+ auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
+ if (!binary_or_err) {
+ BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
+ binary_or_err.getError().message().c_str());
+ return nothing;
+ }
+ return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
+ std::move(buffer_or_err.get()));
+}
+
static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
- if (!IsValidElfPath(filename)) {
- return nullptr;
+ llvm::object::OwningBinary<llvm::object::Binary> owning_binary;
+ if (filename.find("!/") != std::string::npos) {
+ owning_binary = OpenEmbeddedElfFile(filename);
+ } else {
+ if (!IsValidElfPath(filename)) {
+ return nullptr;
+ }
+ auto binary_or_err = llvm::object::createBinary(llvm::StringRef(filename));
+ if (!binary_or_err) {
+ return nullptr;
+ }
+ owning_binary = std::move(binary_or_err.get());
}
- auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
- if (owning_binary.getError()) {
- return nullptr;
- }
- llvm::object::Binary* binary = owning_binary.get().getBinary();
+ llvm::object::Binary* binary = owning_binary.getBinary();
auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
if (obj == nullptr) {
return nullptr;
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 696237d..059f170 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -105,12 +105,6 @@
if (logId > LOG_ID_SECURITY) {
return -EINVAL;
}
- if (logId == LOG_ID_SECURITY) {
- uid_t uid = __android_log_uid();
- if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
- return -EPERM;
- }
- }
if (logdLoggerWrite.context.sock < 0) {
if (access("/dev/socket/logdw", W_OK) == 0) {
return 0;
diff --git a/liblog/logger.h b/liblog/logger.h
index 61bc396..5d031d7 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -40,6 +40,7 @@
struct android_log_transport_write {
struct listnode node;
const char *name;
+ unsigned logMask; /* cache of available success */
union android_log_context context; /* Initialized by static allocation */
int (*available)(log_id_t logId);
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index f15c7cd..0d6ba08 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -26,6 +26,7 @@
#include <cutils/list.h>
#include <log/log.h>
#include <log/logger.h>
+#include <private/android_filesystem_config.h>
#include "config_read.h"
#include "log_portability.h"
@@ -91,6 +92,10 @@
logger_for_each(logger, logger_list) {
log_id_t logId = logger->logId;
+ if ((logId == LOG_ID_SECURITY) &&
+ (__android_log_uid() != AID_SYSTEM)) {
+ continue;
+ }
if (transport->read &&
(!transport->available ||
(transport->available(logId) >= 0))) {
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index a4155e9..b802ed7 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -49,20 +49,85 @@
kLogUninitialized, kLogNotAvailable, kLogAvailable
} g_log_status = kLogUninitialized;
+static int check_log_uid_permissions()
+{
+#if defined(__BIONIC__)
+ uid_t uid = __android_log_uid();
+
+ /* Matches clientHasLogCredentials() in logd */
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+ uid = geteuid();
+ if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+ gid_t gid = getgid();
+ if ((gid != AID_SYSTEM) &&
+ (gid != AID_ROOT) &&
+ (gid != AID_LOG)) {
+ gid = getegid();
+ if ((gid != AID_SYSTEM) &&
+ (gid != AID_ROOT) &&
+ (gid != AID_LOG)) {
+ int num_groups;
+ gid_t *groups;
+
+ num_groups = getgroups(0, NULL);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
+ groups = calloc(num_groups, sizeof(gid_t));
+ if (!groups) {
+ return -ENOMEM;
+ }
+ num_groups = getgroups(num_groups, groups);
+ while (num_groups > 0) {
+ if (groups[num_groups - 1] == AID_LOG) {
+ break;
+ }
+ --num_groups;
+ }
+ free(groups);
+ if (num_groups <= 0) {
+ return -EPERM;
+ }
+ }
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+static void __android_log_cache_available(
+ struct android_log_transport_write *node)
+{
+ size_t i;
+
+ if (node->logMask) {
+ return;
+ }
+
+ for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ if (node->write &&
+ (i != LOG_ID_KERNEL) &&
+ ((i != LOG_ID_SECURITY) ||
+ (check_log_uid_permissions() == 0)) &&
+ (!node->available || ((*node->available)(i) >= 0))) {
+ node->logMask |= 1 << i;
+ }
+ }
+}
+
LIBLOG_ABI_PUBLIC int __android_log_dev_available()
{
struct android_log_transport_write *node;
- size_t i;
if (list_empty(&__android_log_transport_write)) {
return kLogUninitialized;
}
- for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- write_transport_for_each(node, &__android_log_transport_write) {
- if (node->write &&
- (!node->available || ((*node->available)(i) >= 0))) {
- return kLogAvailable;
- }
+
+ write_transport_for_each(node, &__android_log_transport_write) {
+ __android_log_cache_available(node);
+ if (node->logMask) {
+ return kLogAvailable;
}
}
return kLogNotAvailable;
@@ -77,6 +142,11 @@
__android_log_config_write();
write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+ __android_log_cache_available(transport);
+ if (!transport->logMask) {
+ list_remove(&transport->node);
+ continue;
+ }
if (!transport->open || ((*transport->open)() < 0)) {
if (transport->close) {
(*transport->close)();
@@ -87,6 +157,11 @@
++ret;
}
write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+ __android_log_cache_available(transport);
+ if (!transport->logMask) {
+ list_remove(&transport->node);
+ continue;
+ }
if (!transport->open || ((*transport->open)() < 0)) {
if (transport->close) {
(*transport->close)();
@@ -127,50 +202,13 @@
#if defined(__BIONIC__)
if (log_id == LOG_ID_SECURITY) {
- uid_t uid;
-
if (vec[0].iov_len < 4) {
return -EINVAL;
}
- uid = __android_log_uid();
- /* Matches clientHasLogCredentials() in logd */
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- uid = geteuid();
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- gid_t gid = getgid();
- if ((gid != AID_SYSTEM) &&
- (gid != AID_ROOT) &&
- (gid != AID_LOG)) {
- gid = getegid();
- if ((gid != AID_SYSTEM) &&
- (gid != AID_ROOT) &&
- (gid != AID_LOG)) {
- int num_groups;
- gid_t *groups;
-
- num_groups = getgroups(0, NULL);
- if (num_groups <= 0) {
- return -EPERM;
- }
- groups = calloc(num_groups, sizeof(gid_t));
- if (!groups) {
- return -ENOMEM;
- }
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- free(groups);
- if (num_groups <= 0) {
- return -EPERM;
- }
- }
- }
- }
+ ret = check_log_uid_permissions();
+ if (ret < 0) {
+ return ret;
}
if (!__android_log_security()) {
/* If only we could reset downstream logd counter */
@@ -262,8 +300,9 @@
#endif
ret = 0;
+ i = 1 << log_id;
write_transport_for_each(node, &__android_log_transport_write) {
- if (node->write) {
+ if (node->logMask & i) {
ssize_t retval;
retval = (*node->write)(log_id, &ts, vec, nr);
if (ret >= 0) {
@@ -273,7 +312,7 @@
}
write_transport_for_each(node, &__android_log_persist_write) {
- if (node->write) {
+ if (node->logMask & i) {
(void)(*node->write)(log_id, &ts, vec, nr);
}
}
@@ -343,12 +382,12 @@
}
#endif
- vec[0].iov_base = (unsigned char *) &prio;
- vec[0].iov_len = 1;
- vec[1].iov_base = (void *) tag;
- vec[1].iov_len = strlen(tag) + 1;
- vec[2].iov_base = (void *) msg;
- vec[2].iov_len = strlen(msg) + 1;
+ vec[0].iov_base = (unsigned char *)&prio;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *)tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void *)msg;
+ vec[2].iov_len = strlen(msg) + 1;
return write_to_log(bufID, vec, 3);
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index d7de864..9b60d4a 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -512,8 +512,18 @@
}
if (msgStart == -1) {
- fprintf(stderr, "+++ LOG: malformed log message\n");
- return -1;
+ /* +++ LOG: malformed log message, DYB */
+ for (i = 1; i < buf->len; i++) {
+ /* odd characters in tag? */
+ if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
+ msg[i] = '\0';
+ msgStart = i + 1;
+ break;
+ }
+ }
+ if (msgStart == -1) {
+ msgStart = buf->len - 1; /* All tag, no message, print truncates */
+ }
}
if (msgEnd == -1) {
/* incoming message not null-terminated; force it */
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 941b9b9..456f8b3 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1065,8 +1065,10 @@
fflush(stderr);
int printLogLine =
android_log_printLogLine(logformat, fileno(stderr), &entry);
+ // Legacy tag truncation
EXPECT_LE(128, printLogLine);
- EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD, printLogLine);
+ // Measured maximum if we try to print part of the tag as message
+ EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
}
android_log_format_free(logformat);
}
diff --git a/libmemunreachable/ProcessMappings.cpp b/libmemunreachable/ProcessMappings.cpp
index 7cca7c1..57b2321 100644
--- a/libmemunreachable/ProcessMappings.cpp
+++ b/libmemunreachable/ProcessMappings.cpp
@@ -30,11 +30,10 @@
bool ProcessMappings(pid_t pid, allocator::vector<Mapping>& mappings) {
char map_buffer[1024];
snprintf(map_buffer, sizeof(map_buffer), "/proc/%d/maps", pid);
- int fd = open(map_buffer, O_RDONLY);
- if (fd < 0) {
+ android::base::unique_fd fd(open(map_buffer, O_RDONLY));
+ if (fd == -1) {
return false;
}
- android::base::unique_fd fd_guard{fd};
LineBuffer line_buf(fd, map_buffer, sizeof(map_buffer));
char* line;
diff --git a/libmemunreachable/ThreadCapture.cpp b/libmemunreachable/ThreadCapture.cpp
index e8a8392..9155c29 100644
--- a/libmemunreachable/ThreadCapture.cpp
+++ b/libmemunreachable/ThreadCapture.cpp
@@ -108,12 +108,11 @@
strlcat(path, pid_str, sizeof(path));
strlcat(path, "/task", sizeof(path));
- int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
- if (fd < 0) {
+ android::base::unique_fd fd(open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
+ if (fd == -1) {
ALOGE("failed to open %s: %s", path, strerror(errno));
return false;
}
- android::base::unique_fd fd_guard{fd};
struct linux_dirent64 {
uint64_t d_ino;
@@ -125,7 +124,7 @@
char dirent_buf[4096];
ssize_t nread;
do {
- nread = syscall(SYS_getdents64, fd, dirent_buf, sizeof(dirent_buf));
+ nread = syscall(SYS_getdents64, fd.get(), dirent_buf, sizeof(dirent_buf));
if (nread < 0) {
ALOGE("failed to get directory entries from %s: %s", path, strerror(errno));
return false;
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp
index cefe94e..41ed84e 100644
--- a/libmemunreachable/tests/ThreadCapture_test.cpp
+++ b/libmemunreachable/tests/ThreadCapture_test.cpp
@@ -28,8 +28,6 @@
#include <gtest/gtest.h>
-#include <android-base/unique_fd.h>
-
#include "Allocator.h"
#include "ScopedDisableMalloc.h"
#include "ScopedPipe.h"
diff --git a/logcat/Android.mk b/logcat/Android.mk
index b828a9f..1dacbe1 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -5,7 +5,7 @@
LOCAL_SRC_FILES:= logcat.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils libpcrecpp
LOCAL_MODULE := logcat
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index c148d89..cc3333c 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -37,6 +37,8 @@
#include <log/logprint.h>
#include <system/thread_defs.h>
+#include <pcrecpp.h>
+
#define DEFAULT_MAX_ROTATED_LOGS 4
static AndroidLogFormat * g_logformat;
@@ -76,6 +78,10 @@
static size_t g_outByteCount = 0;
static int g_printBinary = 0;
static int g_devCount = 0; // >1 means multiple
+static pcrecpp::RE* g_regex;
+// 0 means "infinite"
+static size_t g_maxCount = 0;
+static size_t g_printCount = 0;
__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
@@ -143,6 +149,21 @@
TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
}
+static bool regexOk(const AndroidLogEntry& entry, log_id_t id)
+{
+ if (! g_regex) {
+ return true;
+ }
+
+ if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
+ return false;
+ }
+
+ std::string messageString(entry.message, entry.messageLen);
+
+ return g_regex->PartialMatch(messageString);
+}
+
static void processBuffer(log_device_t* dev, struct log_msg *buf)
{
int bytesWritten = 0;
@@ -171,9 +192,12 @@
goto error;
}
- if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+ if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority) &&
+ regexOk(entry, buf->id())) {
bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
+ g_printCount++;
+
if (bytesWritten < 0) {
logcat_panic(false, "output error");
}
@@ -271,6 +295,10 @@
" -c clear (flush) the entire log and exit\n"
" --clear\n"
" -d dump the log and then exit (don't block)\n"
+ " -e <expr> only print lines where the log message matches <expr>\n"
+ " --regex <expr> where <expr> is a regular expression\n"
+ " -m <count> quit after printing <count> lines. This is meant to be\n"
+ " --max-count=<count> paired with --regex, but will work on its own.\n"
" -t <count> print only the most recent <count> lines (implies -d)\n"
" -t '<time>' print most recent lines since specified time (implies -d)\n"
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
@@ -521,6 +549,7 @@
size_t tail_lines = 0;
log_time tail_time(log_time::EPOCH);
size_t pid = 0;
+ bool got_t = false;
signal(SIGPIPE, exit);
@@ -547,7 +576,9 @@
{ "format", required_argument, NULL, 'v' },
{ "last", no_argument, NULL, 'L' },
{ pid_str, required_argument, NULL, 0 },
+ { "max-count", required_argument, NULL, 'm' },
{ "prune", optional_argument, NULL, 'p' },
+ { "regex", required_argument, NULL, 'e' },
{ "rotate_count", required_argument, NULL, 'n' },
{ "rotate_kbytes", required_argument, NULL, 'r' },
{ "statistics", no_argument, NULL, 'S' },
@@ -556,7 +587,7 @@
{ NULL, 0, NULL, 0 }
};
- ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:",
+ ret = getopt_long(argc, argv, ":cdDLt:T:gG:sQf:r:n:v:b:BSpP:m:e:",
long_options, &option_index);
if (ret < 0) {
@@ -613,6 +644,7 @@
break;
case 't':
+ got_t = true;
mode |= ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
/* FALLTHRU */
case 'T':
@@ -644,6 +676,19 @@
printDividers = true;
break;
+ case 'e':
+ g_regex = new pcrecpp::RE(optarg);
+ break;
+
+ case 'm': {
+ char *end = NULL;
+ if (!getSizeTArg(optarg, &g_maxCount)) {
+ logcat_panic(false, "-%c \"%s\" isn't an "
+ "integer greater than zero\n", ret, optarg);
+ }
+ }
+ break;
+
case 'g':
if (!optarg) {
getLogSize = 1;
@@ -920,6 +965,10 @@
}
}
+ if (g_maxCount && got_t) {
+ logcat_panic(true, "Cannot use -m (--max-count) and -t together");
+ }
+
if (!devices) {
dev = devices = new log_device_t("main", false);
g_devCount = 1;
@@ -1135,7 +1184,8 @@
dev = NULL;
log_device_t unexpected("unexpected", false);
- while (1) {
+
+ while (!g_maxCount || g_printCount < g_maxCount) {
struct log_msg log_msg;
log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 8459bd3..c6eb7f8 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -953,3 +953,67 @@
free(list);
list = NULL;
}
+
+TEST(logcat, regex) {
+ FILE *fp;
+ int count = 0;
+
+ char buffer[5120];
+
+ 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"));
+
+ // Let the logs settle
+ sleep(1);
+
+ ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ continue;
+ }
+
+ EXPECT_TRUE(strstr(buffer, "logcat_test_") != NULL);
+
+ count++;
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(2, count);
+}
+
+TEST(logcat, maxcount) {
+ FILE *fp;
+ int count = 0;
+
+ char buffer[5120];
+
+ snprintf(buffer, sizeof(buffer), "logcat --pid %d -d --max-count 3", getpid());
+
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+ LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
+
+ // Let the logs settle
+ sleep(1);
+
+ ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ continue;
+ }
+
+ count++;
+ }
+
+ pclose(fp);
+
+ ASSERT_EQ(3, count);
+}
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index 7b04bcc..5a13da2 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -102,12 +102,12 @@
def parse_os_version(x):
match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
if match:
- a = parse_int(match.group(1))
+ a = int(match.group(1))
b = c = 0
if match.lastindex >= 2:
- b = parse_int(match.group(2))
+ b = int(match.group(2))
if match.lastindex == 3:
- c = parse_int(match.group(3))
+ c = int(match.group(3))
# 7 bits allocated for each field
assert a < 128
assert b < 128
@@ -118,8 +118,8 @@
def parse_os_patch_level(x):
match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x)
if match:
- y = parse_int(match.group(1)) - 2000
- m = parse_int(match.group(2))
+ y = int(match.group(1)) - 2000
+ m = int(match.group(2))
# 7 bits allocated for the year, 4 bits for the month
assert y >= 0 and y < 128
assert m > 0 and m <= 12