diff --git a/base/.clang-format b/base/.clang-format deleted file mode 120000 index fd0645fdf..000000000 --- a/base/.clang-format +++ /dev/null @@ -1 +0,0 @@ -../.clang-format-2 \ No newline at end of file diff --git a/base/Android.bp b/base/Android.bp deleted file mode 100644 index 6d8544aa6..000000000 --- a/base/Android.bp +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (C) 2015 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. -// - -cc_defaults { - name: "libbase_cflags_defaults", - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - ], - target: { - android: { - cflags: [ - "-D_FILE_OFFSET_BITS=64", - ], - }, - }, -} - -cc_library_headers { - name: "libbase_headers", - vendor_available: true, - ramdisk_available: true, - recovery_available: true, - host_supported: true, - native_bridge_supported: true, - export_include_dirs: ["include"], - - target: { - linux_bionic: { - enabled: true, - }, - windows: { - enabled: true, - }, - }, - apex_available: [ - "//apex_available:anyapex", - "//apex_available:platform", - ], - min_sdk_version: "29", -} - -cc_defaults { - name: "libbase_defaults", - defaults: ["libbase_cflags_defaults"], - srcs: [ - "chrono_utils.cpp", - "cmsg.cpp", - "file.cpp", - "liblog_symbols.cpp", - "logging.cpp", - "mapped_file.cpp", - "parsebool.cpp", - "parsenetaddress.cpp", - "process.cpp", - "properties.cpp", - "stringprintf.cpp", - "strings.cpp", - "threads.cpp", - "test_utils.cpp", - ], - - cppflags: ["-Wexit-time-destructors"], - shared_libs: ["liblog"], - target: { - android: { - sanitize: { - misc_undefined: ["integer"], - }, - - }, - linux: { - srcs: [ - "errors_unix.cpp", - ], - }, - darwin: { - srcs: [ - "errors_unix.cpp", - ], - }, - linux_bionic: { - enabled: true, - }, - windows: { - srcs: [ - "errors_windows.cpp", - "utf8.cpp", - ], - exclude_srcs: [ - "cmsg.cpp", - ], - enabled: true, - }, - }, -} - -cc_library { - name: "libbase", - defaults: ["libbase_defaults"], - vendor_available: true, - ramdisk_available: true, - recovery_available: true, - host_supported: true, - native_bridge_supported: true, - vndk: { - enabled: true, - support_system_process: true, - }, - header_libs: [ - "libbase_headers", - ], - export_header_lib_headers: ["libbase_headers"], - static_libs: ["fmtlib"], - whole_static_libs: ["fmtlib"], - export_static_lib_headers: ["fmtlib"], - apex_available: [ - "//apex_available:anyapex", - "//apex_available:platform", - ], - min_sdk_version: "29", -} - -cc_library_static { - name: "libbase_ndk", - defaults: ["libbase_defaults"], - sdk_version: "current", - stl: "c++_static", - export_include_dirs: ["include"], - static_libs: ["fmtlib_ndk"], - whole_static_libs: ["fmtlib_ndk"], - export_static_lib_headers: ["fmtlib_ndk"], -} - -// Tests -// ------------------------------------------------------------------------------ -cc_test { - name: "libbase_test", - defaults: ["libbase_cflags_defaults"], - host_supported: true, - srcs: [ - "cmsg_test.cpp", - "endian_test.cpp", - "errors_test.cpp", - "expected_test.cpp", - "file_test.cpp", - "logging_splitters_test.cpp", - "logging_test.cpp", - "macros_test.cpp", - "mapped_file_test.cpp", - "no_destructor_test.cpp", - "parsedouble_test.cpp", - "parsebool_test.cpp", - "parseint_test.cpp", - "parsenetaddress_test.cpp", - "process_test.cpp", - "properties_test.cpp", - "result_test.cpp", - "scopeguard_test.cpp", - "stringprintf_test.cpp", - "strings_test.cpp", - "test_main.cpp", - "test_utils_test.cpp", - ], - target: { - android: { - sanitize: { - misc_undefined: ["integer"], - }, - }, - linux: { - srcs: ["chrono_utils_test.cpp"], - }, - windows: { - srcs: ["utf8_test.cpp"], - cflags: ["-Wno-unused-parameter"], - enabled: true, - }, - }, - local_include_dirs: ["."], - shared_libs: ["libbase"], - compile_multilib: "both", - multilib: { - lib32: { - suffix: "32", - }, - lib64: { - suffix: "64", - }, - }, - test_suites: ["device-tests"], -} - -cc_test { - name: "libbase_tidy_test", - defaults: ["libbase_cflags_defaults"], - host_supported: true, - - tidy: true, - tidy_checks_as_errors: ["bugprone-use-after-move"], - - srcs: [ - "tidy/unique_fd_test.cpp", - "tidy/unique_fd_test2.cpp", - ], - - shared_libs: ["libbase"], - test_suites: ["device_tests"], -} - -cc_benchmark { - name: "libbase_benchmark", - defaults: ["libbase_cflags_defaults"], - - srcs: ["format_benchmark.cpp"], - shared_libs: ["libbase"], - - compile_multilib: "both", - multilib: { - lib32: { - suffix: "32", - }, - lib64: { - suffix: "64", - }, - }, -} diff --git a/base/CPPLINT.cfg b/base/CPPLINT.cfg deleted file mode 100644 index d94a89c34..000000000 --- a/base/CPPLINT.cfg +++ /dev/null @@ -1,2 +0,0 @@ -set noparent -filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators diff --git a/base/OWNERS b/base/OWNERS deleted file mode 100644 index 97777f703..000000000 --- a/base/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -enh@google.com -jmgao@google.com -tomcherry@google.com diff --git a/base/README.md b/base/README.md deleted file mode 100644 index 2ef5c10b5..000000000 --- a/base/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# libbase - -## Who is this library for? - -This library is a collection of convenience functions to make common tasks -easier and less error-prone. - -In this context, "error-prone" covers both "hard to do correctly" and -"hard to do with good performance", but as a general purpose library, -libbase's primary focus is on making it easier to do things easily and -correctly when a compromise has to be made between "simplest API" on the -one hand and "fastest implementation" on the other. Though obviously -the ideal is to have both. - -## Should my routine be added? - -The intention is to cover the 80% use cases, not be all things to all users. - -If you have a routine that's really useful in your project, -congratulations. But that doesn't mean it should be here rather than -just in your project. - -The question for libbase is "should everyone be doing this?"/"does this -make everyone's code cleaner/safer?". Historically we've considered the -bar for inclusion to be "are there at least three *unrelated* projects -that would be cleaned up by doing so". - -If your routine is actually something from a future C++ standard (that -isn't yet in libc++), or it's widely used in another library, that helps -show that there's precedent. Being able to say "so-and-so has used this -API for n years" is a good way to reduce concerns about API choices. - -## Any other restrictions? - -Unlike most Android code, code in libbase has to build for Mac and -Windows too. - -Code here is also expected to have good test coverage. - -By its nature, it's difficult to change libbase API. It's often best -to start using your routine just in your project, and let it "graduate" -after you're certain that the API is solid. diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp deleted file mode 100644 index 19080a5a7..000000000 --- a/base/chrono_utils.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 "android-base/chrono_utils.h" - -#include - -namespace android { -namespace base { - -boot_clock::time_point boot_clock::now() { -#ifdef __linux__ - timespec ts; - clock_gettime(CLOCK_BOOTTIME, &ts); - return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) + - std::chrono::nanoseconds(ts.tv_nsec)); -#else - // Darwin and Windows do not support clock_gettime. - return boot_clock::time_point(); -#endif // __linux__ -} - -std::ostream& operator<<(std::ostream& os, const Timer& t) { - os << t.duration().count() << "ms"; - return os; -} - -} // namespace base -} // namespace android diff --git a/base/chrono_utils_test.cpp b/base/chrono_utils_test.cpp deleted file mode 100644 index da442f455..000000000 --- a/base/chrono_utils_test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 "android-base/chrono_utils.h" - -#include - -#include -#include -#include -#include - -#include - -namespace android { -namespace base { - -std::chrono::seconds GetBootTimeSeconds() { - struct timespec now; - clock_gettime(CLOCK_BOOTTIME, &now); - - auto now_tp = boot_clock::time_point(std::chrono::seconds(now.tv_sec) + - std::chrono::nanoseconds(now.tv_nsec)); - return std::chrono::duration_cast(now_tp.time_since_epoch()); -} - -// Tests (at least) the seconds accuracy of the boot_clock::now() method. -TEST(ChronoUtilsTest, BootClockNowSeconds) { - auto now = GetBootTimeSeconds(); - auto boot_seconds = - std::chrono::duration_cast(boot_clock::now().time_since_epoch()); - EXPECT_EQ(now, boot_seconds); -} - -template -void ExpectAboutEqual(T expected, T actual) { - auto expected_upper_bound = expected * 1.05f; - auto expected_lower_bound = expected * .95; - EXPECT_GT(expected_upper_bound, actual); - EXPECT_LT(expected_lower_bound, actual); -} - -TEST(ChronoUtilsTest, TimerDurationIsSane) { - auto start = boot_clock::now(); - Timer t; - std::this_thread::sleep_for(50ms); - auto stop = boot_clock::now(); - auto stop_timer = t.duration(); - - auto expected = std::chrono::duration_cast(stop - start); - ExpectAboutEqual(expected, stop_timer); -} - -TEST(ChronoUtilsTest, TimerOstream) { - Timer t; - std::this_thread::sleep_for(50ms); - auto stop_timer = t.duration().count(); - std::stringstream os; - os << t; - decltype(stop_timer) stop_timer_from_stream; - os >> stop_timer_from_stream; - EXPECT_NE(0, stop_timer); - ExpectAboutEqual(stop_timer, stop_timer_from_stream); -} - -} // namespace base -} // namespace android diff --git a/base/cmsg.cpp b/base/cmsg.cpp deleted file mode 100644 index 1fa873c82..000000000 --- a/base/cmsg.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2019 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 - -#include - -namespace android { -namespace base { - -ssize_t SendFileDescriptorVector(borrowed_fd sockfd, const void* data, size_t len, - const std::vector& fds) { - size_t cmsg_space = CMSG_SPACE(sizeof(int) * fds.size()); - size_t cmsg_len = CMSG_LEN(sizeof(int) * fds.size()); - if (cmsg_space >= PAGE_SIZE) { - errno = ENOMEM; - return -1; - } - - alignas(struct cmsghdr) char cmsg_buf[cmsg_space]; - iovec iov = {.iov_base = const_cast(data), .iov_len = len}; - msghdr msg = { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsg_buf, - // We can't cast to the actual type of the field, because it's different across platforms. - .msg_controllen = static_cast(cmsg_space), - .msg_flags = 0, - }; - - struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = cmsg_len; - - int* cmsg_fds = reinterpret_cast(CMSG_DATA(cmsg)); - for (size_t i = 0; i < fds.size(); ++i) { - cmsg_fds[i] = fds[i]; - } - -#if defined(__linux__) - int flags = MSG_NOSIGNAL; -#else - int flags = 0; -#endif - - return TEMP_FAILURE_RETRY(sendmsg(sockfd.get(), &msg, flags)); -} - -ssize_t ReceiveFileDescriptorVector(borrowed_fd sockfd, void* data, size_t len, size_t max_fds, - std::vector* fds) { - fds->clear(); - - size_t cmsg_space = CMSG_SPACE(sizeof(int) * max_fds); - if (cmsg_space >= PAGE_SIZE) { - errno = ENOMEM; - return -1; - } - - alignas(struct cmsghdr) char cmsg_buf[cmsg_space]; - iovec iov = {.iov_base = const_cast(data), .iov_len = len}; - msghdr msg = { - .msg_name = nullptr, - .msg_namelen = 0, - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsg_buf, - // We can't cast to the actual type of the field, because it's different across platforms. - .msg_controllen = static_cast(cmsg_space), - .msg_flags = 0, - }; - - int flags = MSG_TRUNC | MSG_CTRUNC; -#if defined(__linux__) - flags |= MSG_CMSG_CLOEXEC | MSG_NOSIGNAL; -#endif - - ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sockfd.get(), &msg, flags)); - - if (rc == -1) { - return -1; - } - - int error = 0; - if ((msg.msg_flags & MSG_TRUNC)) { - LOG(ERROR) << "message was truncated when receiving file descriptors"; - error = EMSGSIZE; - } else if ((msg.msg_flags & MSG_CTRUNC)) { - LOG(ERROR) << "control message was truncated when receiving file descriptors"; - error = EMSGSIZE; - } - - std::vector received_fds; - struct cmsghdr* cmsg; - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - LOG(ERROR) << "received unexpected cmsg: [" << cmsg->cmsg_level << ", " << cmsg->cmsg_type - << "]"; - error = EBADMSG; - continue; - } - - // There isn't a macro that does the inverse of CMSG_LEN, so hack around it ourselves, with - // some asserts to ensure that CMSG_LEN behaves as we expect. -#if defined(__linux__) -#define CMSG_ASSERT static_assert -#else -// CMSG_LEN is somehow not constexpr on darwin. -#define CMSG_ASSERT CHECK -#endif - CMSG_ASSERT(CMSG_LEN(0) + 1 * sizeof(int) == CMSG_LEN(1 * sizeof(int))); - CMSG_ASSERT(CMSG_LEN(0) + 2 * sizeof(int) == CMSG_LEN(2 * sizeof(int))); - CMSG_ASSERT(CMSG_LEN(0) + 3 * sizeof(int) == CMSG_LEN(3 * sizeof(int))); - CMSG_ASSERT(CMSG_LEN(0) + 4 * sizeof(int) == CMSG_LEN(4 * sizeof(int))); - - if (cmsg->cmsg_len % sizeof(int) != 0) { - LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not aligned to sizeof(int)"; - } else if (cmsg->cmsg_len <= CMSG_LEN(0)) { - LOG(FATAL) << "cmsg_len(" << cmsg->cmsg_len << ") not long enough to hold any data"; - } - - int* cmsg_fds = reinterpret_cast(CMSG_DATA(cmsg)); - size_t cmsg_fdcount = static_cast(cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - for (size_t i = 0; i < cmsg_fdcount; ++i) { -#if !defined(__linux__) - // Linux uses MSG_CMSG_CLOEXEC instead of doing this manually. - fcntl(cmsg_fds[i], F_SETFD, FD_CLOEXEC); -#endif - received_fds.emplace_back(cmsg_fds[i]); - } - } - - if (error != 0) { - errno = error; - return -1; - } - - if (received_fds.size() > max_fds) { - LOG(ERROR) << "received too many file descriptors, expected " << fds->size() << ", received " - << received_fds.size(); - errno = EMSGSIZE; - return -1; - } - - *fds = std::move(received_fds); - return rc; -} - -} // namespace base -} // namespace android diff --git a/base/cmsg_test.cpp b/base/cmsg_test.cpp deleted file mode 100644 index 9ee5c8253..000000000 --- a/base/cmsg_test.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2019 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 - -#if !defined(_WIN32) - -using android::base::ReceiveFileDescriptors; -using android::base::SendFileDescriptors; -using android::base::unique_fd; - -static ino_t GetInode(int fd) { - struct stat st; - if (fstat(fd, &st) != 0) { - PLOG(FATAL) << "fstat failed"; - } - - return st.st_ino; -} - -struct CmsgTest : ::testing::TestWithParam { - bool Seqpacket() { return GetParam(); } - - void SetUp() override { - ASSERT_TRUE( - android::base::Socketpair(Seqpacket() ? SOCK_SEQPACKET : SOCK_STREAM, &send, &recv)); - int dup1 = dup(tmp1.fd); - ASSERT_NE(-1, dup1); - int dup2 = dup(tmp2.fd); - ASSERT_NE(-1, dup2); - - fd1.reset(dup1); - fd2.reset(dup2); - - ino1 = GetInode(dup1); - ino2 = GetInode(dup2); - } - - unique_fd send; - unique_fd recv; - - TemporaryFile tmp1; - TemporaryFile tmp2; - - unique_fd fd1; - unique_fd fd2; - - ino_t ino1; - ino_t ino2; -}; - -TEST_P(CmsgTest, smoke) { - ASSERT_EQ(1, SendFileDescriptors(send.get(), "x", 1, fd1.get())); - - char buf[2]; - unique_fd received; - ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 2, &received)); - ASSERT_EQ('x', buf[0]); - ASSERT_NE(-1, received.get()); - - ASSERT_EQ(ino1, GetInode(received.get())); -} - -TEST_P(CmsgTest, msg_trunc) { - ASSERT_EQ(2, SendFileDescriptors(send.get(), "ab", 2, fd1.get(), fd2.get())); - - char buf[2]; - unique_fd received1, received2; - - ssize_t rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2); - if (Seqpacket()) { - ASSERT_EQ(-1, rc); - ASSERT_EQ(EMSGSIZE, errno); - ASSERT_EQ(-1, received1.get()); - ASSERT_EQ(-1, received2.get()); - } else { - ASSERT_EQ(1, rc); - ASSERT_NE(-1, received1.get()); - ASSERT_NE(-1, received2.get()); - ASSERT_EQ(ino1, GetInode(received1.get())); - ASSERT_EQ(ino2, GetInode(received2.get())); - ASSERT_EQ(1, read(recv.get(), buf, 2)); - } -} - -TEST_P(CmsgTest, msg_ctrunc) { - ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get())); - - char buf[2]; - unique_fd received; - ASSERT_EQ(-1, ReceiveFileDescriptors(recv.get(), buf, 1, &received)); - ASSERT_EQ(EMSGSIZE, errno); - ASSERT_EQ(-1, received.get()); -} - -TEST_P(CmsgTest, peek) { - ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get())); - - char buf[2]; - ASSERT_EQ(1, ::recv(recv.get(), buf, sizeof(buf), MSG_PEEK)); - ASSERT_EQ('a', buf[0]); - - unique_fd received; - ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received)); - ASSERT_EQ(ino1, GetInode(received.get())); -} - -TEST_P(CmsgTest, stream_fd_association) { - if (Seqpacket()) { - return; - } - - // fds are associated with the first byte of the write. - ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(send.get(), "a", 1))); - ASSERT_EQ(2, SendFileDescriptors(send.get(), "bc", 2, fd1.get())); - ASSERT_EQ(1, SendFileDescriptors(send.get(), "d", 1, fd2.get())); - char buf[2]; - ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(recv.get(), buf, 2))); - ASSERT_EQ(0, memcmp(buf, "ab", 2)); - - std::vector received1; - ssize_t rc = ReceiveFileDescriptorVector(recv.get(), buf, 1, 1, &received1); - ASSERT_EQ(1, rc); - ASSERT_EQ('c', buf[0]); - ASSERT_TRUE(received1.empty()); - - unique_fd received2; - rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received2); - ASSERT_EQ(1, rc); - ASSERT_EQ('d', buf[0]); - ASSERT_EQ(ino2, GetInode(received2.get())); -} - -TEST_P(CmsgTest, multiple_fd_ordering) { - ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get())); - - char buf[2]; - unique_fd received1, received2; - ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2)); - - ASSERT_NE(-1, received1.get()); - ASSERT_NE(-1, received2.get()); - - ASSERT_EQ(ino1, GetInode(received1.get())); - ASSERT_EQ(ino2, GetInode(received2.get())); -} - -TEST_P(CmsgTest, separate_fd_ordering) { - ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get())); - ASSERT_EQ(1, SendFileDescriptors(send.get(), "b", 1, fd2.get())); - - char buf[2]; - unique_fd received1, received2; - ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1)); - ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received2)); - - ASSERT_NE(-1, received1.get()); - ASSERT_NE(-1, received2.get()); - - ASSERT_EQ(ino1, GetInode(received1.get())); - ASSERT_EQ(ino2, GetInode(received2.get())); -} - -TEST_P(CmsgTest, separate_fds_no_coalescing) { - unique_fd sent1(dup(tmp1.fd)); - unique_fd sent2(dup(tmp2.fd)); - - ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd1.get())); - ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd2.get())); - - char buf[2]; - std::vector received; - ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received)); - ASSERT_EQ(1U, received.size()); - ASSERT_EQ(ino1, GetInode(received[0].get())); - - ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received)); - ASSERT_EQ(1U, received.size()); - ASSERT_EQ(ino2, GetInode(received[0].get())); -} - -INSTANTIATE_TEST_CASE_P(CmsgTest, CmsgTest, testing::Bool()); - -#endif diff --git a/base/endian_test.cpp b/base/endian_test.cpp deleted file mode 100644 index 963ab1348..000000000 --- a/base/endian_test.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 "android-base/endian.h" - -#include - -TEST(endian, constants) { - ASSERT_TRUE(__LITTLE_ENDIAN == LITTLE_ENDIAN); - ASSERT_TRUE(__BIG_ENDIAN == BIG_ENDIAN); - ASSERT_TRUE(__BYTE_ORDER == BYTE_ORDER); - - ASSERT_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); -} - -TEST(endian, smoke) { - static constexpr uint16_t le16 = 0x1234; - static constexpr uint32_t le32 = 0x12345678; - static constexpr uint64_t le64 = 0x123456789abcdef0; - - static constexpr uint16_t be16 = 0x3412; - static constexpr uint32_t be32 = 0x78563412; - static constexpr uint64_t be64 = 0xf0debc9a78563412; - - ASSERT_EQ(be16, htons(le16)); - ASSERT_EQ(be32, htonl(le32)); - ASSERT_EQ(be64, htonq(le64)); - - ASSERT_EQ(le16, ntohs(be16)); - ASSERT_EQ(le32, ntohl(be32)); - ASSERT_EQ(le64, ntohq(be64)); - - ASSERT_EQ(be16, htobe16(le16)); - ASSERT_EQ(be32, htobe32(le32)); - ASSERT_EQ(be64, htobe64(le64)); - - ASSERT_EQ(le16, betoh16(be16)); - ASSERT_EQ(le32, betoh32(be32)); - ASSERT_EQ(le64, betoh64(be64)); - - ASSERT_EQ(le16, htole16(le16)); - ASSERT_EQ(le32, htole32(le32)); - ASSERT_EQ(le64, htole64(le64)); - - ASSERT_EQ(le16, letoh16(le16)); - ASSERT_EQ(le32, letoh32(le32)); - ASSERT_EQ(le64, letoh64(le64)); - - ASSERT_EQ(le16, be16toh(be16)); - ASSERT_EQ(le32, be32toh(be32)); - ASSERT_EQ(le64, be64toh(be64)); - - ASSERT_EQ(le16, le16toh(le16)); - ASSERT_EQ(le32, le32toh(le32)); - ASSERT_EQ(le64, le64toh(le64)); -} diff --git a/base/errors_test.cpp b/base/errors_test.cpp deleted file mode 100644 index 8e7cdd1da..000000000 --- a/base/errors_test.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/errors.h" - -#include - -namespace android { -namespace base { - -// Error strings aren't consistent enough across systems to test the output, -// just make sure we can compile correctly and nothing crashes even if we send -// it possibly bogus error codes. -TEST(ErrorsTest, TestSystemErrorString) { - SystemErrorCodeToString(-1); - SystemErrorCodeToString(0); - SystemErrorCodeToString(1); -} - -} // namespace base -} // namespace android diff --git a/base/errors_unix.cpp b/base/errors_unix.cpp deleted file mode 100644 index 48269b675..000000000 --- a/base/errors_unix.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/errors.h" - -#include -#include - -namespace android { -namespace base { - -std::string SystemErrorCodeToString(int error_code) { - return strerror(error_code); -} - -} // namespace base -} // namespace android diff --git a/base/errors_windows.cpp b/base/errors_windows.cpp deleted file mode 100644 index a5ff51188..000000000 --- a/base/errors_windows.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/errors.h" - -#include - -#include "android-base/stringprintf.h" -#include "android-base/strings.h" -#include "android-base/utf8.h" - -// A Windows error code is a DWORD. It's simpler to use an int error code for -// both Unix and Windows if possible, but if this fails we'll need a different -// function signature for each. -static_assert(sizeof(int) >= sizeof(DWORD), - "Windows system error codes are too large to fit in an int."); - -namespace android { -namespace base { - -static constexpr DWORD kErrorMessageBufferSize = 256; - -std::string SystemErrorCodeToString(int int_error_code) { - WCHAR msgbuf[kErrorMessageBufferSize]; - DWORD error_code = int_error_code; - DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf, - kErrorMessageBufferSize, nullptr); - if (len == 0) { - return android::base::StringPrintf( - "Error %lu while retrieving message for error %lu", GetLastError(), - error_code); - } - - // Convert UTF-16 to UTF-8. - std::string msg; - if (!android::base::WideToUTF8(msgbuf, &msg)) { - return android::base::StringPrintf( - "Error %lu while converting message for error %lu from UTF-16 to UTF-8", - GetLastError(), error_code); - } - - // Messages returned by the system end with line breaks. - msg = android::base::Trim(msg); - - // There are many Windows error messages compared to POSIX, so include the - // numeric error code for easier, quicker, accurate identification. Use - // decimal instead of hex because there are decimal ranges like 10000-11999 - // for Winsock. - android::base::StringAppendF(&msg, " (%lu)", error_code); - return msg; -} - -} // namespace base -} // namespace android diff --git a/base/expected_test.cpp b/base/expected_test.cpp deleted file mode 100644 index 47e396a22..000000000 --- a/base/expected_test.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/expected.h" - -#include -#include -#include - -#include - -using android::base::expected; -using android::base::unexpected; - -typedef expected exp_int; -typedef expected exp_double; -typedef expected exp_string; -typedef expected, int> exp_pair; -typedef expected exp_void; - -struct T { - int a; - int b; - T() = default; - T(int a, int b) noexcept : a(a), b(b) {} -}; -bool operator==(const T& x, const T& y) { - return x.a == y.a && x.b == y.b; -} -bool operator!=(const T& x, const T& y) { - return x.a != y.a || x.b != y.b; -} - -struct E { - std::string message; - int cause; - E(const std::string& message, int cause) : message(message), cause(cause) {} -}; - -typedef expected exp_complex; - -TEST(Expected, testDefaultConstructible) { - exp_int e; - EXPECT_TRUE(e.has_value()); - EXPECT_EQ(0, e.value()); - - exp_complex e2; - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(T(0,0), e2.value()); - - exp_void e3; - EXPECT_TRUE(e3.has_value()); -} - -TEST(Expected, testCopyConstructible) { - exp_int e; - exp_int e2 = e; - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(0, e.value()); - EXPECT_EQ(0, e2.value()); - - exp_void e3; - exp_void e4 = e3; - EXPECT_TRUE(e3.has_value()); - EXPECT_TRUE(e4.has_value()); -} - -TEST(Expected, testMoveConstructible) { - exp_int e; - exp_int e2 = std::move(e); - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(0, e.value()); - EXPECT_EQ(0, e2.value()); - - exp_string e3(std::string("hello")); - exp_string e4 = std::move(e3); - - EXPECT_TRUE(e3.has_value()); - EXPECT_TRUE(e4.has_value()); - EXPECT_EQ("", e3.value()); // e3 is moved - EXPECT_EQ("hello", e4.value()); - - exp_void e5; - exp_void e6 = std::move(e5); - EXPECT_TRUE(e5.has_value()); - EXPECT_TRUE(e6.has_value()); -} - -TEST(Expected, testCopyConstructibleFromConvertibleType) { - exp_double e = 3.3f; - exp_int e2 = e; - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(3.3f, e.value()); - EXPECT_EQ(3, e2.value()); -} - -TEST(Expected, testMoveConstructibleFromConvertibleType) { - exp_double e = 3.3f; - exp_int e2 = std::move(e); - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(3.3f, e.value()); - EXPECT_EQ(3, e2.value()); -} - -TEST(Expected, testConstructibleFromValue) { - exp_int e = 3; - exp_double e2 = 5.5f; - exp_string e3 = std::string("hello"); - exp_complex e4 = T(10, 20); - exp_void e5 = {}; - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_TRUE(e3.has_value()); - EXPECT_TRUE(e4.has_value()); - EXPECT_TRUE(e5.has_value()); - EXPECT_EQ(3, e.value()); - EXPECT_EQ(5.5f, e2.value()); - EXPECT_EQ("hello", e3.value()); - EXPECT_EQ(T(10,20), e4.value()); -} - -TEST(Expected, testConstructibleFromMovedValue) { - std::string hello = "hello"; - exp_string e = std::move(hello); - - EXPECT_TRUE(e.has_value()); - EXPECT_EQ("hello", e.value()); - EXPECT_EQ("", hello); -} - -TEST(Expected, testConstructibleFromConvertibleValue) { - exp_int e = 3.3f; // double to int - exp_string e2 = "hello"; // char* to std::string - EXPECT_TRUE(e.has_value()); - EXPECT_EQ(3, e.value()); - - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ("hello", e2.value()); -} - -TEST(Expected, testConstructibleFromUnexpected) { - exp_int::unexpected_type unexp = unexpected(10); - exp_int e = unexp; - - exp_double::unexpected_type unexp2 = unexpected(10.5f); - exp_double e2 = unexp2; - - exp_string::unexpected_type unexp3 = unexpected(std::string("error")); - exp_string e3 = unexp3; - - exp_void::unexpected_type unexp4 = unexpected(10); - exp_void e4 = unexp4; - - EXPECT_FALSE(e.has_value()); - EXPECT_FALSE(e2.has_value()); - EXPECT_FALSE(e3.has_value()); - EXPECT_FALSE(e4.has_value()); - EXPECT_EQ(10, e.error()); - EXPECT_EQ(10.5f, e2.error()); - EXPECT_EQ("error", e3.error()); - EXPECT_EQ(10, e4.error()); -} - -TEST(Expected, testMoveConstructibleFromUnexpected) { - exp_int e = unexpected(10); - exp_double e2 = unexpected(10.5f); - exp_string e3 = unexpected(std::string("error")); - exp_void e4 = unexpected(10); - - EXPECT_FALSE(e.has_value()); - EXPECT_FALSE(e2.has_value()); - EXPECT_FALSE(e3.has_value()); - EXPECT_FALSE(e4.has_value()); - EXPECT_EQ(10, e.error()); - EXPECT_EQ(10.5f, e2.error()); - EXPECT_EQ("error", e3.error()); - EXPECT_EQ(10, e4.error()); -} - -TEST(Expected, testConstructibleByForwarding) { - exp_string e(std::in_place, 5, 'a'); - EXPECT_TRUE(e.has_value()); - EXPECT_EQ("aaaaa", e.value()); - - exp_string e2({'a', 'b', 'c'}); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ("abc", e2.value()); - - exp_pair e3({"hello", 30}); - EXPECT_TRUE(e3.has_value()); - EXPECT_EQ("hello",e3->first); - EXPECT_EQ(30,e3->second); - - exp_void e4({}); - EXPECT_TRUE(e4.has_value()); -} - -TEST(Expected, testDestructible) { - bool destroyed = false; - struct T { - bool* flag_; - T(bool* flag) : flag_(flag) {} - ~T() { *flag_ = true; } - }; - { - expected exp = T(&destroyed); - } - EXPECT_TRUE(destroyed); -} - -TEST(Expected, testAssignable) { - exp_int e = 10; - exp_int e2 = 20; - e = e2; - - EXPECT_EQ(20, e.value()); - EXPECT_EQ(20, e2.value()); - - exp_int e3 = 10; - exp_int e4 = 20; - e3 = std::move(e4); - - EXPECT_EQ(20, e3.value()); - EXPECT_EQ(20, e4.value()); - - exp_void e5 = unexpected(10); - ASSERT_FALSE(e5.has_value()); - exp_void e6; - e5 = e6; - - EXPECT_TRUE(e5.has_value()); - EXPECT_TRUE(e6.has_value()); -} - -TEST(Expected, testAssignableFromValue) { - exp_int e = 10; - e = 20; - EXPECT_EQ(20, e.value()); - - exp_double e2 = 3.5f; - e2 = 10.5f; - EXPECT_EQ(10.5f, e2.value()); - - exp_string e3 = "hello"; - e3 = "world"; - EXPECT_EQ("world", e3.value()); - - exp_void e4 = unexpected(10); - ASSERT_FALSE(e4.has_value()); - e4 = {}; - EXPECT_TRUE(e4.has_value()); -} - -TEST(Expected, testAssignableFromUnexpected) { - exp_int e = 10; - e = unexpected(30); - EXPECT_FALSE(e.has_value()); - EXPECT_EQ(30, e.error()); - - exp_double e2 = 3.5f; - e2 = unexpected(10.5f); - EXPECT_FALSE(e2.has_value()); - EXPECT_EQ(10.5f, e2.error()); - - exp_string e3 = "hello"; - e3 = unexpected("world"); - EXPECT_FALSE(e3.has_value()); - EXPECT_EQ("world", e3.error()); - - exp_void e4 = {}; - e4 = unexpected(10); - EXPECT_FALSE(e4.has_value()); - EXPECT_EQ(10, e4.error()); -} - -TEST(Expected, testAssignableFromMovedValue) { - std::string world = "world"; - exp_string e = "hello"; - e = std::move(world); - - EXPECT_TRUE(e.has_value()); - EXPECT_EQ("world", e.value()); - EXPECT_EQ("", world); -} - -TEST(Expected, testAssignableFromMovedUnexpected) { - std::string world = "world"; - exp_string e = "hello"; - e = unexpected(std::move(world)); - - EXPECT_FALSE(e.has_value()); - EXPECT_EQ("world", e.error()); - EXPECT_EQ("", world); -} - -TEST(Expected, testEmplace) { - struct T { - int a; - double b; - T() {} - T(int a, double b) noexcept : a(a), b(b) {} - }; - expected exp; - T& t = exp.emplace(3, 10.5f); - - EXPECT_TRUE(exp.has_value()); - EXPECT_EQ(3, t.a); - EXPECT_EQ(10.5f, t.b); - EXPECT_EQ(3, exp.value().a); - EXPECT_EQ(10.5, exp.value().b); - - exp_void e = unexpected(10); - ASSERT_FALSE(e.has_value()); - e.emplace(); - EXPECT_TRUE(e.has_value()); -} - -TEST(Expected, testSwapExpectedExpected) { - exp_int e = 10; - exp_int e2 = 20; - e.swap(e2); - - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(20, e.value()); - EXPECT_EQ(10, e2.value()); - - exp_void e3; - exp_void e4; - e3.swap(e4); - - EXPECT_TRUE(e3.has_value()); - EXPECT_TRUE(e4.has_value()); -} - -TEST(Expected, testSwapUnexpectedUnexpected) { - exp_int e = unexpected(10); - exp_int e2 = unexpected(20); - e.swap(e2); - EXPECT_FALSE(e.has_value()); - EXPECT_FALSE(e2.has_value()); - EXPECT_EQ(20, e.error()); - EXPECT_EQ(10, e2.error()); - - exp_void e3 = unexpected(10); - exp_void e4 = unexpected(20); - e3.swap(e4); - EXPECT_FALSE(e3.has_value()); - EXPECT_FALSE(e4.has_value()); - EXPECT_EQ(20, e3.error()); - EXPECT_EQ(10, e4.error()); -} - -TEST(Expected, testSwapExpectedUnepected) { - exp_int e = 10; - exp_int e2 = unexpected(30); - e.swap(e2); - EXPECT_FALSE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(30, e.error()); - EXPECT_EQ(10, e2.value()); - - exp_void e3; - exp_void e4 = unexpected(10); - e3.swap(e4); - EXPECT_FALSE(e3.has_value()); - EXPECT_TRUE(e4.has_value()); - EXPECT_EQ(10, e3.error()); -} - -TEST(Expected, testDereference) { - struct T { - int a; - double b; - T() {} - T(int a, double b) : a(a), b(b) {} - }; - expected exp = T(3, 10.5f); - - EXPECT_EQ(3, exp->a); - EXPECT_EQ(10.5f, exp->b); - - EXPECT_EQ(3, (*exp).a); - EXPECT_EQ(10.5f, (*exp).b); -} - -TEST(Expected, testTest) { - exp_int e = 10; - EXPECT_TRUE(e.ok()); - EXPECT_TRUE(e.has_value()); - - exp_int e2 = unexpected(10); - EXPECT_FALSE(e2.ok()); - EXPECT_FALSE(e2.has_value()); -} - -TEST(Expected, testGetValue) { - exp_int e = 10; - EXPECT_EQ(10, e.value()); - EXPECT_EQ(10, e.value_or(20)); - - exp_int e2 = unexpected(10); - EXPECT_EQ(10, e2.error()); - EXPECT_EQ(20, e2.value_or(20)); -} - -TEST(Expected, testSameValues) { - exp_int e = 10; - exp_int e2 = 10; - EXPECT_TRUE(e == e2); - EXPECT_TRUE(e2 == e); - EXPECT_FALSE(e != e2); - EXPECT_FALSE(e2 != e); - - exp_void e3; - exp_void e4; - EXPECT_TRUE(e3 == e4); - EXPECT_TRUE(e4 == e3); - EXPECT_FALSE(e3 != e4); - EXPECT_FALSE(e4 != e3); -} - -TEST(Expected, testDifferentValues) { - exp_int e = 10; - exp_int e2 = 20; - EXPECT_FALSE(e == e2); - EXPECT_FALSE(e2 == e); - EXPECT_TRUE(e != e2); - EXPECT_TRUE(e2 != e); -} - -TEST(Expected, testValueWithError) { - exp_int e = 10; - exp_int e2 = unexpected(10); - EXPECT_FALSE(e == e2); - EXPECT_FALSE(e2 == e); - EXPECT_TRUE(e != e2); - EXPECT_TRUE(e2 != e); - - exp_void e3; - exp_void e4 = unexpected(10); - EXPECT_FALSE(e3 == e4); - EXPECT_FALSE(e4 == e3); - EXPECT_TRUE(e3 != e4); - EXPECT_TRUE(e4 != e3); -} - -TEST(Expected, testSameErrors) { - exp_int e = unexpected(10); - exp_int e2 = unexpected(10); - EXPECT_TRUE(e == e2); - EXPECT_TRUE(e2 == e); - EXPECT_FALSE(e != e2); - EXPECT_FALSE(e2 != e); - - exp_void e3 = unexpected(10); - exp_void e4 = unexpected(10); - EXPECT_TRUE(e3 == e4); - EXPECT_TRUE(e4 == e3); - EXPECT_FALSE(e3 != e4); - EXPECT_FALSE(e4 != e3); -} - -TEST(Expected, testDifferentErrors) { - exp_int e = unexpected(10); - exp_int e2 = unexpected(20); - EXPECT_FALSE(e == e2); - EXPECT_FALSE(e2 == e); - EXPECT_TRUE(e != e2); - EXPECT_TRUE(e2 != e); - - exp_void e3 = unexpected(10); - exp_void e4 = unexpected(20); - EXPECT_FALSE(e3 == e4); - EXPECT_FALSE(e4 == e3); - EXPECT_TRUE(e3 != e4); - EXPECT_TRUE(e4 != e3); -} - -TEST(Expected, testCompareWithSameError) { - exp_int e = unexpected(10); - exp_int::unexpected_type error = 10; - EXPECT_TRUE(e == error); - EXPECT_TRUE(error == e); - EXPECT_FALSE(e != error); - EXPECT_FALSE(error != e); - - exp_void e2 = unexpected(10); - exp_void::unexpected_type error2 = 10; - EXPECT_TRUE(e2 == error2); - EXPECT_TRUE(error2 == e2); - EXPECT_FALSE(e2 != error2); - EXPECT_FALSE(error2 != e2); -} - -TEST(Expected, testCompareWithDifferentError) { - exp_int e = unexpected(10); - exp_int::unexpected_type error = 20; - EXPECT_FALSE(e == error); - EXPECT_FALSE(error == e); - EXPECT_TRUE(e != error); - EXPECT_TRUE(error != e); - - exp_void e2 = unexpected(10); - exp_void::unexpected_type error2 = 20; - EXPECT_FALSE(e2 == error2); - EXPECT_FALSE(error2 == e2); - EXPECT_TRUE(e2 != error2); - EXPECT_TRUE(error2 != e2); -} - -TEST(Expected, testCompareDifferentType) { - expected e = 10; - expected e2 = 10; - EXPECT_TRUE(e == e2); - e2 = 20; - EXPECT_FALSE(e == e2); - - expected e3 = "hello"; - expected e4 = "hello"; - EXPECT_TRUE(e3 == e4); - e4 = "world"; - EXPECT_FALSE(e3 == e4); - - expected e5; - expected e6 = 10; - EXPECT_FALSE(e5 == e6); - EXPECT_FALSE(e6 == e5); -} - -TEST(Expected, testDivideExample) { - struct QR { - int quotient; - int remainder; - QR(int q, int r) noexcept : quotient(q), remainder(r) {} - bool operator==(const QR& rhs) const { - return quotient == rhs.quotient && remainder == rhs.remainder; - } - bool operator!=(const QR& rhs) const { - return quotient != rhs.quotient || remainder == rhs.remainder; - } - }; - - auto divide = [](int x, int y) -> expected { - if (y == 0) { - return unexpected(E("divide by zero", -1)); - } else { - return QR(x / y, x % y); - } - }; - - EXPECT_FALSE(divide(10, 0).ok()); - EXPECT_EQ("divide by zero", divide(10, 0).error().message); - EXPECT_EQ(-1, divide(10, 0).error().cause); - - EXPECT_TRUE(divide(10, 3).ok()); - EXPECT_EQ(QR(3, 1), *divide(10, 3)); -} - -TEST(Expected, testPair) { - auto test = [](bool yes) -> exp_pair { - if (yes) { - return exp_pair({"yes", 42}); - } else { - return unexpected(42); - } - }; - - auto r = test(true); - EXPECT_TRUE(r.ok()); - EXPECT_EQ("yes", r->first); -} - -TEST(Expected, testVoid) { - auto test = [](bool ok) -> exp_void { - if (ok) { - return {}; - } else { - return unexpected(10); - } - }; - - auto r = test(true); - EXPECT_TRUE(r.ok()); - r = test(false); - EXPECT_FALSE(r.ok()); - EXPECT_EQ(10, r.error()); -} - -// copied from result_test.cpp -struct ConstructorTracker { - static size_t constructor_called; - static size_t copy_constructor_called; - static size_t move_constructor_called; - static size_t copy_assignment_called; - static size_t move_assignment_called; - - template >* = nullptr> - ConstructorTracker(T&& string) : string(string) { - ++constructor_called; - } - ConstructorTracker(const ConstructorTracker& ct) { - ++copy_constructor_called; - string = ct.string; - } - ConstructorTracker(ConstructorTracker&& ct) noexcept { - ++move_constructor_called; - string = std::move(ct.string); - } - ConstructorTracker& operator=(const ConstructorTracker& ct) { - ++copy_assignment_called; - string = ct.string; - return *this; - } - ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept { - ++move_assignment_called; - string = std::move(ct.string); - return *this; - } - static void Reset() { - constructor_called = 0; - copy_constructor_called = 0; - move_constructor_called = 0; - copy_assignment_called = 0; - move_assignment_called = 0; - } - std::string string; -}; - -size_t ConstructorTracker::constructor_called = 0; -size_t ConstructorTracker::copy_constructor_called = 0; -size_t ConstructorTracker::move_constructor_called = 0; -size_t ConstructorTracker::copy_assignment_called = 0; -size_t ConstructorTracker::move_assignment_called = 0; - -typedef expected exp_track; - -TEST(Expected, testNumberOfCopies) { - // default constructor - ConstructorTracker::Reset(); - exp_track e("hello"); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // copy constructor - ConstructorTracker::Reset(); - exp_track e2 = e; - EXPECT_EQ(0U, ConstructorTracker::constructor_called); - EXPECT_EQ(1U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // move constructor - ConstructorTracker::Reset(); - exp_track e3 = std::move(e); - EXPECT_EQ(0U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // construct from lvalue - ConstructorTracker::Reset(); - ConstructorTracker ct = "hello"; - exp_track e4(ct); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(1U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // construct from rvalue - ConstructorTracker::Reset(); - ConstructorTracker ct2 = "hello"; - exp_track e5(std::move(ct2)); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // copy assignment - ConstructorTracker::Reset(); - exp_track e6 = "hello"; - exp_track e7 = "world"; - e7 = e6; - EXPECT_EQ(2U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - // move assignment - ConstructorTracker::Reset(); - exp_track e8 = "hello"; - exp_track e9 = "world"; - e9 = std::move(e8); - EXPECT_EQ(2U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(1U, ConstructorTracker::move_assignment_called); - - // swap - ConstructorTracker::Reset(); - exp_track e10 = "hello"; - exp_track e11 = "world"; - std::swap(e10, e11); - EXPECT_EQ(2U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(2U, ConstructorTracker::move_assignment_called); -} - -TEST(Expected, testNoCopyOnReturn) { - auto test = [](const std::string& in) -> exp_track { - if (in.empty()) { - return "literal string"; - } - if (in == "test2") { - return ConstructorTracker(in + in + "2"); - } - ConstructorTracker result(in + " " + in); - return result; - }; - - ConstructorTracker::Reset(); - auto result1 = test(""); - ASSERT_TRUE(result1.ok()); - EXPECT_EQ("literal string", result1->string); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - ConstructorTracker::Reset(); - auto result2 = test("test2"); - ASSERT_TRUE(result2.ok()); - EXPECT_EQ("test2test22", result2->string); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - ConstructorTracker::Reset(); - auto result3 = test("test3"); - ASSERT_TRUE(result3.ok()); - EXPECT_EQ("test3 test3", result3->string); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); -} - -TEST(Expected, testNested) { - expected e = "hello"; - - EXPECT_TRUE(e.ok()); - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e.value().has_value()); - EXPECT_TRUE(e->ok()); - EXPECT_EQ("hello", e.value().value()); - - expected e2 = unexpected("world"); - EXPECT_FALSE(e2.has_value()); - EXPECT_FALSE(e2.ok()); - EXPECT_EQ("world", e2.error()); - - expected e3 = exp_string(unexpected("world")); - EXPECT_TRUE(e3.has_value()); - EXPECT_FALSE(e3.value().has_value()); - EXPECT_TRUE(e3.ok()); - EXPECT_FALSE(e3->ok()); - EXPECT_EQ("world", e3.value().error()); -} - -constexpr bool equals(const char* a, const char* b) { - return (a == nullptr && b == nullptr) || - (a != nullptr && b != nullptr && *a == *b && - (*a == '\0' || equals(a + 1, b + 1))); -} - -TEST(Expected, testConstexpr) { - // Compliation error will occur if these expressions can't be - // evaluated at compile time - constexpr exp_int e(3); - constexpr exp_int::unexpected_type err(3); - constexpr int i = 4; - - // default constructor - static_assert(exp_int().value() == 0); - // copy constructor - static_assert(exp_int(e).value() == 3); - // move constructor - static_assert(exp_int(exp_int(4)).value() == 4); - // copy construct from value - static_assert(exp_int(i).value() == 4); - // copy construct from unexpected - static_assert(exp_int(err).error() == 3); - // move costruct from unexpected - static_assert(exp_int(unexpected(3)).error() == 3); - // observers - static_assert(*exp_int(3) == 3); - static_assert(exp_int(3).has_value() == true); - static_assert(exp_int(3).value_or(4) == 3); - - typedef expected exp_s; - constexpr exp_s s("hello"); - constexpr const char* c = "hello"; - static_assert(equals(exp_s().value(), nullptr)); - static_assert(equals(exp_s(s).value(), "hello")); - static_assert(equals(exp_s(exp_s("hello")).value(), "hello")); - static_assert(equals(exp_s("hello").value(), "hello")); - static_assert(equals(exp_s(c).value(), "hello")); -} - -TEST(Expected, testWithNonConstructible) { - struct AssertNotConstructed { - AssertNotConstructed() = delete; - }; - - expected v(42); - EXPECT_TRUE(v.has_value()); - EXPECT_EQ(42, v.value()); - - expected e(unexpected(42)); - EXPECT_FALSE(e.has_value()); - EXPECT_EQ(42, e.error()); -} - -TEST(Expected, testWithMoveOnlyType) { - typedef expected,std::unique_ptr> exp_ptr; - exp_ptr e(std::make_unique(3)); - exp_ptr e2(unexpected(std::make_unique(4))); - - EXPECT_TRUE(e.has_value()); - EXPECT_FALSE(e2.has_value()); - EXPECT_EQ(3, *(e.value())); - EXPECT_EQ(4, *(e2.error())); - - e2 = std::move(e); - EXPECT_TRUE(e.has_value()); - EXPECT_TRUE(e2.has_value()); - EXPECT_EQ(3, *(e2.value())); -} diff --git a/base/file.cpp b/base/file.cpp deleted file mode 100644 index 97cc2b27f..000000000 --- a/base/file.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/file.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(__APPLE__) -#include -#endif -#if defined(_WIN32) -#include -#include -#define O_NOFOLLOW 0 -#define OS_PATH_SEPARATOR '\\' -#else -#define OS_PATH_SEPARATOR '/' -#endif - -#include "android-base/logging.h" // and must be after windows.h for ERROR -#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin. -#include "android-base/unique_fd.h" -#include "android-base/utf8.h" - -namespace { - -#ifdef _WIN32 -static int mkstemp(char* name_template, size_t size_in_chars) { - std::wstring path; - CHECK(android::base::UTF8ToWide(name_template, &path)) - << "path can't be converted to wchar: " << name_template; - if (_wmktemp_s(path.data(), path.size() + 1) != 0) { - return -1; - } - - // Use open() to match the close() that TemporaryFile's destructor does. - // Use O_BINARY to match base file APIs. - int fd = _wopen(path.c_str(), O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR); - if (fd < 0) { - return -1; - } - - std::string path_utf8; - CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8"; - CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0) - << "utf8 path can't be assigned back to name_template"; - - return fd; -} - -static char* mkdtemp(char* name_template, size_t size_in_chars) { - std::wstring path; - CHECK(android::base::UTF8ToWide(name_template, &path)) - << "path can't be converted to wchar: " << name_template; - - if (_wmktemp_s(path.data(), path.size() + 1) != 0) { - return nullptr; - } - - if (_wmkdir(path.c_str()) != 0) { - return nullptr; - } - - std::string path_utf8; - CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8"; - CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0) - << "utf8 path can't be assigned back to name_template"; - - return name_template; -} -#endif - -std::string GetSystemTempDir() { -#if defined(__ANDROID__) - const auto* tmpdir = getenv("TMPDIR"); - if (tmpdir == nullptr) tmpdir = "/data/local/tmp"; - if (access(tmpdir, R_OK | W_OK | X_OK) == 0) { - return tmpdir; - } - // Tests running in app context can't access /data/local/tmp, - // so try current directory if /data/local/tmp is not accessible. - return "."; -#elif defined(_WIN32) - wchar_t tmp_dir_w[MAX_PATH]; - DWORD result = GetTempPathW(std::size(tmp_dir_w), tmp_dir_w); // checks TMP env - CHECK_NE(result, 0ul) << "GetTempPathW failed, error: " << GetLastError(); - CHECK_LT(result, std::size(tmp_dir_w)) << "path truncated to: " << result; - - // GetTempPath() returns a path with a trailing slash, but init() - // does not expect that, so remove it. - if (tmp_dir_w[result - 1] == L'\\') { - tmp_dir_w[result - 1] = L'\0'; - } - - std::string tmp_dir; - CHECK(android::base::WideToUTF8(tmp_dir_w, &tmp_dir)) << "path can't be converted to utf8"; - - return tmp_dir; -#else - const auto* tmpdir = getenv("TMPDIR"); - if (tmpdir == nullptr) tmpdir = "/tmp"; - return tmpdir; -#endif -} - -} // namespace - -TemporaryFile::TemporaryFile() { - init(GetSystemTempDir()); -} - -TemporaryFile::TemporaryFile(const std::string& tmp_dir) { - init(tmp_dir); -} - -TemporaryFile::~TemporaryFile() { - if (fd != -1) { - close(fd); - } - if (remove_file_) { - unlink(path); - } -} - -int TemporaryFile::release() { - int result = fd; - fd = -1; - return result; -} - -void TemporaryFile::init(const std::string& tmp_dir) { - snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR); -#if defined(_WIN32) - fd = mkstemp(path, sizeof(path)); -#else - fd = mkstemp(path); -#endif -} - -TemporaryDir::TemporaryDir() { - init(GetSystemTempDir()); -} - -TemporaryDir::~TemporaryDir() { - if (!remove_dir_and_contents_) return; - - auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int { - switch (file_type) { - case FTW_D: - case FTW_DP: - case FTW_DNR: - if (rmdir(child) == -1) { - PLOG(ERROR) << "rmdir " << child; - } - break; - case FTW_NS: - default: - if (rmdir(child) != -1) break; - // FALLTHRU (for gcc, lint, pcc, etc; and following for clang) - FALLTHROUGH_INTENDED; - case FTW_F: - case FTW_SL: - case FTW_SLN: - if (unlink(child) == -1) { - PLOG(ERROR) << "unlink " << child; - } - break; - } - return 0; - }; - - nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS); -} - -bool TemporaryDir::init(const std::string& tmp_dir) { - snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR); -#if defined(_WIN32) - return (mkdtemp(path, sizeof(path)) != nullptr); -#else - return (mkdtemp(path) != nullptr); -#endif -} - -namespace android { -namespace base { - -// Versions of standard library APIs that support UTF-8 strings. -using namespace android::base::utf8; - -bool ReadFdToString(borrowed_fd fd, std::string* content) { - content->clear(); - - // Although original we had small files in mind, this code gets used for - // very large files too, where the std::string growth heuristics might not - // be suitable. https://code.google.com/p/android/issues/detail?id=258500. - struct stat sb; - if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) { - content->reserve(sb.st_size); - } - - char buf[BUFSIZ] __attribute__((__uninitialized__)); - ssize_t n; - while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) { - content->append(buf, n); - } - return (n == 0) ? true : false; -} - -bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) { - content->clear(); - - int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW); - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags))); - if (fd == -1) { - return false; - } - return ReadFdToString(fd, content); -} - -bool WriteStringToFd(const std::string& content, borrowed_fd fd) { - const char* p = content.data(); - size_t left = content.size(); - while (left > 0) { - ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left)); - if (n == -1) { - return false; - } - p += n; - left -= n; - } - return true; -} - -static bool CleanUpAfterFailedWrite(const std::string& path) { - // Something went wrong. Let's not leave a corrupt file lying around. - int saved_errno = errno; - unlink(path.c_str()); - errno = saved_errno; - return false; -} - -#if !defined(_WIN32) -bool WriteStringToFile(const std::string& content, const std::string& path, - mode_t mode, uid_t owner, gid_t group, - bool follow_symlinks) { - int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY | - (follow_symlinks ? 0 : O_NOFOLLOW); - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode))); - if (fd == -1) { - PLOG(ERROR) << "android::WriteStringToFile open failed"; - return false; - } - - // We do an explicit fchmod here because we assume that the caller really - // meant what they said and doesn't want the umask-influenced mode. - if (fchmod(fd, mode) == -1) { - PLOG(ERROR) << "android::WriteStringToFile fchmod failed"; - return CleanUpAfterFailedWrite(path); - } - if (fchown(fd, owner, group) == -1) { - PLOG(ERROR) << "android::WriteStringToFile fchown failed"; - return CleanUpAfterFailedWrite(path); - } - if (!WriteStringToFd(content, fd)) { - PLOG(ERROR) << "android::WriteStringToFile write failed"; - return CleanUpAfterFailedWrite(path); - } - return true; -} -#endif - -bool WriteStringToFile(const std::string& content, const std::string& path, - bool follow_symlinks) { - int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY | - (follow_symlinks ? 0 : O_NOFOLLOW); - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0666))); - if (fd == -1) { - return false; - } - return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path); -} - -bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) { - uint8_t* p = reinterpret_cast(data); - size_t remaining = byte_count; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining)); - if (n <= 0) return false; - p += n; - remaining -= n; - } - return true; -} - -#if defined(_WIN32) -// Windows implementation of pread. Note that this DOES move the file descriptors read position, -// but it does so atomically. -static ssize_t pread(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) { - DWORD bytes_read; - OVERLAPPED overlapped; - memset(&overlapped, 0, sizeof(OVERLAPPED)); - overlapped.Offset = static_cast(offset); - overlapped.OffsetHigh = static_cast(offset >> 32); - if (!ReadFile(reinterpret_cast(_get_osfhandle(fd.get())), data, - static_cast(byte_count), &bytes_read, &overlapped)) { - // In case someone tries to read errno (since this is masquerading as a POSIX call) - errno = EIO; - return -1; - } - return static_cast(bytes_read); -} -#endif - -bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) { - uint8_t* p = reinterpret_cast(data); - while (byte_count > 0) { - ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), p, byte_count, offset)); - if (n <= 0) return false; - p += n; - byte_count -= n; - offset += n; - } - return true; -} - -bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) { - const uint8_t* p = reinterpret_cast(data); - size_t remaining = byte_count; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining)); - if (n == -1) return false; - p += n; - remaining -= n; - } - return true; -} - -bool RemoveFileIfExists(const std::string& path, std::string* err) { - struct stat st; -#if defined(_WIN32) - // TODO: Windows version can't handle symbolic links correctly. - int result = stat(path.c_str(), &st); - bool file_type_removable = (result == 0 && S_ISREG(st.st_mode)); -#else - int result = lstat(path.c_str(), &st); - bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))); -#endif - if (result == -1) { - if (errno == ENOENT || errno == ENOTDIR) return true; - if (err != nullptr) *err = strerror(errno); - return false; - } - - if (result == 0) { - if (!file_type_removable) { - if (err != nullptr) { - *err = "is not a regular file or symbolic link"; - } - return false; - } - if (unlink(path.c_str()) == -1) { - if (err != nullptr) { - *err = strerror(errno); - } - return false; - } - } - return true; -} - -#if !defined(_WIN32) -bool Readlink(const std::string& path, std::string* result) { - result->clear(); - - // Most Linux file systems (ext2 and ext4, say) limit symbolic links to - // 4095 bytes. Since we'll copy out into the string anyway, it doesn't - // waste memory to just start there. We add 1 so that we can recognize - // whether it actually fit (rather than being truncated to 4095). - std::vector buf(4095 + 1); - while (true) { - ssize_t size = readlink(path.c_str(), &buf[0], buf.size()); - // Unrecoverable error? - if (size == -1) return false; - // It fit! (If size == buf.size(), it may have been truncated.) - if (static_cast(size) < buf.size()) { - result->assign(&buf[0], size); - return true; - } - // Double our buffer and try again. - buf.resize(buf.size() * 2); - } -} -#endif - -#if !defined(_WIN32) -bool Realpath(const std::string& path, std::string* result) { - result->clear(); - - // realpath may exit with EINTR. Retry if so. - char* realpath_buf = nullptr; - do { - realpath_buf = realpath(path.c_str(), nullptr); - } while (realpath_buf == nullptr && errno == EINTR); - - if (realpath_buf == nullptr) { - return false; - } - result->assign(realpath_buf); - free(realpath_buf); - return true; -} -#endif - -std::string GetExecutablePath() { -#if defined(__linux__) - std::string path; - android::base::Readlink("/proc/self/exe", &path); - return path; -#elif defined(__APPLE__) - char path[PATH_MAX + 1]; - uint32_t path_len = sizeof(path); - int rc = _NSGetExecutablePath(path, &path_len); - if (rc < 0) { - std::unique_ptr path_buf(new char[path_len]); - _NSGetExecutablePath(path_buf.get(), &path_len); - return path_buf.get(); - } - return path; -#elif defined(_WIN32) - char path[PATH_MAX + 1]; - DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1); - if (result == 0 || result == sizeof(path) - 1) return ""; - path[PATH_MAX - 1] = 0; - return path; -#else -#error unknown OS -#endif -} - -std::string GetExecutableDirectory() { - return Dirname(GetExecutablePath()); -} - -std::string Basename(const std::string& path) { - // Copy path because basename may modify the string passed in. - std::string result(path); - -#if !defined(__BIONIC__) - // Use lock because basename() may write to a process global and return a - // pointer to that. Note that this locking strategy only works if all other - // callers to basename in the process also grab this same lock, but its - // better than nothing. Bionic's basename returns a thread-local buffer. - static std::mutex& basename_lock = *new std::mutex(); - std::lock_guard lock(basename_lock); -#endif - - // Note that if std::string uses copy-on-write strings, &str[0] will cause - // the copy to be made, so there is no chance of us accidentally writing to - // the storage for 'path'. - char* name = basename(&result[0]); - - // In case basename returned a pointer to a process global, copy that string - // before leaving the lock. - result.assign(name); - - return result; -} - -std::string Dirname(const std::string& path) { - // Copy path because dirname may modify the string passed in. - std::string result(path); - -#if !defined(__BIONIC__) - // Use lock because dirname() may write to a process global and return a - // pointer to that. Note that this locking strategy only works if all other - // callers to dirname in the process also grab this same lock, but its - // better than nothing. Bionic's dirname returns a thread-local buffer. - static std::mutex& dirname_lock = *new std::mutex(); - std::lock_guard lock(dirname_lock); -#endif - - // Note that if std::string uses copy-on-write strings, &str[0] will cause - // the copy to be made, so there is no chance of us accidentally writing to - // the storage for 'path'. - char* parent = dirname(&result[0]); - - // In case dirname returned a pointer to a process global, copy that string - // before leaving the lock. - result.assign(parent); - - return result; -} - -} // namespace base -} // namespace android diff --git a/base/file_test.cpp b/base/file_test.cpp deleted file mode 100644 index 120228d94..000000000 --- a/base/file_test.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2013 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 "android-base/file.h" - -#include "android-base/utf8.h" - -#include - -#include -#include -#include -#include - -#include - -#if !defined(_WIN32) -#include -#else -#include -#endif - -#include "android-base/logging.h" // and must be after windows.h for ERROR - -TEST(file, ReadFileToString_ENOENT) { - std::string s("hello"); - errno = 0; - ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s)); - EXPECT_EQ(ENOENT, errno); - EXPECT_EQ("", s); // s was cleared. -} - -TEST(file, ReadFileToString_WriteStringToFile) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path)) - << strerror(errno); - std::string s; - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)) - << strerror(errno); - EXPECT_EQ("abc", s); -} - -// symlinks require elevated privileges on Windows. -#if !defined(_WIN32) -TEST(file, ReadFileToString_WriteStringToFile_symlink) { - TemporaryFile target, link; - ASSERT_EQ(0, unlink(link.path)); - ASSERT_EQ(0, symlink(target.path, link.path)); - ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false)); - ASSERT_EQ(ELOOP, errno); - ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true)); - - std::string s; - ASSERT_FALSE(android::base::ReadFileToString(link.path, &s)); - ASSERT_EQ(ELOOP, errno); - ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true)); - ASSERT_EQ("foo", s); -} -#endif - -// WriteStringToFile2 is explicitly for setting Unix permissions, which make no -// sense on Windows. -#if !defined(_WIN32) -TEST(file, WriteStringToFile2) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660, - getuid(), getgid())) - << strerror(errno); - struct stat sb; - ASSERT_EQ(0, stat(tf.path, &sb)); - ASSERT_EQ(0660U, static_cast(sb.st_mode & ~S_IFMT)); - ASSERT_EQ(getuid(), sb.st_uid); - ASSERT_EQ(getgid(), sb.st_gid); - std::string s; - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)) - << strerror(errno); - EXPECT_EQ("abc", s); -} -#endif - -#if defined(_WIN32) -TEST(file, NonUnicodeCharsWindows) { - constexpr auto kMaxEnvVariableValueSize = 32767; - std::wstring old_tmp; - old_tmp.resize(kMaxEnvVariableValueSize); - old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size())); - if (old_tmp.empty()) { - // Can't continue with empty TMP folder. - return; - } - - std::wstring new_tmp = old_tmp; - if (new_tmp.back() != L'\\') { - new_tmp.push_back(L'\\'); - } - - { - auto path(new_tmp + L"锦绣成都\\"); - _wmkdir(path.c_str()); - ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str())); - - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd)); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno); - EXPECT_EQ("abc", s); - } - { - auto path(new_tmp + L"директория с длинным именем\\"); - _wmkdir(path.c_str()); - ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str())); - - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd)); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno); - EXPECT_EQ("abc", s); - } - { - auto path(new_tmp + L"äüöß weiß\\"); - _wmkdir(path.c_str()); - ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str())); - - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd)); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno); - EXPECT_EQ("abc", s); - } - - SetEnvironmentVariableW(L"TMP", old_tmp.c_str()); -} - -TEST(file, RootDirectoryWindows) { - constexpr auto kMaxEnvVariableValueSize = 32767; - std::wstring old_tmp; - bool tmp_is_empty = false; - old_tmp.resize(kMaxEnvVariableValueSize); - old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size())); - if (old_tmp.empty()) { - tmp_is_empty = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); - } - SetEnvironmentVariableW(L"TMP", L"C:"); - - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - - SetEnvironmentVariableW(L"TMP", tmp_is_empty ? nullptr : old_tmp.c_str()); -} -#endif - -TEST(file, WriteStringToFd) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd)); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - std::string s; - ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno); - EXPECT_EQ("abc", s); -} - -TEST(file, WriteFully) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3)); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - std::string s; - s.resize(3); - ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size())) - << strerror(errno); - EXPECT_EQ("abc", s); - - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno); - - s.resize(1024); - ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size())); -} - -TEST(file, RemoveFileIfExists) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - close(tf.fd); - tf.fd = -1; - std::string err; - ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err; - ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path)); - TemporaryDir td; - ASSERT_FALSE(android::base::RemoveFileIfExists(td.path)); - ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err)); - ASSERT_EQ("is not a regular file or symbolic link", err); -} - -TEST(file, RemoveFileIfExists_ENOTDIR) { - TemporaryFile tf; - close(tf.fd); - tf.fd = -1; - std::string err{"xxx"}; - ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err)); - ASSERT_EQ("xxx", err); -} - -#if !defined(_WIN32) -TEST(file, RemoveFileIfExists_EACCES) { - // EACCES -- one of the directories in the path has no search permission - // root can bypass permission restrictions, so drop root. - if (getuid() == 0) { - passwd* shell = getpwnam("shell"); - setgid(shell->pw_gid); - setuid(shell->pw_uid); - } - - TemporaryDir td; - TemporaryFile tf(td.path); - close(tf.fd); - tf.fd = -1; - std::string err{"xxx"}; - // Remove dir's search permission. - ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0); - ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err)); - ASSERT_EQ("Permission denied", err); - // Set dir's search permission again. - ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0); - ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)); -} -#endif - -TEST(file, Readlink) { -#if !defined(_WIN32) - // Linux doesn't allow empty symbolic links. - std::string min("x"); - // ext2 and ext4 both have PAGE_SIZE limits. - // If file encryption is enabled, there's extra overhead to store the - // size of the encrypted symlink target. There's also an off-by-one - // in current kernels (and marlin/sailfish where we're seeing this - // failure are still on 3.18, far from current). http://b/33306057. - std::string max(static_cast(4096 - 2 - 1 - 1), 'x'); - - TemporaryDir td; - std::string min_path{std::string(td.path) + "/" + "min"}; - std::string max_path{std::string(td.path) + "/" + "max"}; - - ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str())); - ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str())); - - std::string result; - - result = "wrong"; - ASSERT_TRUE(android::base::Readlink(min_path, &result)); - ASSERT_EQ(min, result); - - result = "wrong"; - ASSERT_TRUE(android::base::Readlink(max_path, &result)); - ASSERT_EQ(max, result); -#endif -} - -TEST(file, Realpath) { -#if !defined(_WIN32) - TemporaryDir td; - std::string basename = android::base::Basename(td.path); - std::string dir_name = android::base::Dirname(td.path); - std::string base_dir_name = android::base::Basename(dir_name); - - { - std::string path = dir_name + "/../" + base_dir_name + "/" + basename; - std::string result; - ASSERT_TRUE(android::base::Realpath(path, &result)); - ASSERT_EQ(td.path, result); - } - - { - std::string path = std::string(td.path) + "/.."; - std::string result; - ASSERT_TRUE(android::base::Realpath(path, &result)); - ASSERT_EQ(dir_name, result); - } - - { - errno = 0; - std::string path = std::string(td.path) + "/foo.noent"; - std::string result = "wrong"; - ASSERT_TRUE(!android::base::Realpath(path, &result)); - ASSERT_TRUE(result.empty()); - ASSERT_EQ(ENOENT, errno); - } -#endif -} - -TEST(file, GetExecutableDirectory) { - std::string path = android::base::GetExecutableDirectory(); - ASSERT_NE("", path); - ASSERT_NE(android::base::GetExecutablePath(), path); - ASSERT_EQ('/', path[0]); - ASSERT_NE('/', path[path.size() - 1]); -} - -TEST(file, GetExecutablePath) { - ASSERT_NE("", android::base::GetExecutablePath()); -} - -TEST(file, Basename) { - EXPECT_EQ("sh", android::base::Basename("/system/bin/sh")); - EXPECT_EQ("sh", android::base::Basename("sh")); - EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/")); -} - -TEST(file, Dirname) { - EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh")); - EXPECT_EQ(".", android::base::Dirname("sh")); - EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/")); -} - -TEST(file, ReadFileToString_capacity) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - - // For a huge file, the overhead should still be small. - std::string s; - size_t size = 16 * 1024 * 1024; - ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path)); - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)); - EXPECT_EQ(size, s.size()); - EXPECT_LT(s.capacity(), size + 16); - - // Even for weird badly-aligned sizes. - size += 12345; - ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path)); - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)); - EXPECT_EQ(size, s.size()); - EXPECT_LT(s.capacity(), size + 16); - - // We'll shrink an enormous string if you read a small file into it. - size = 64; - ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path)); - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)); - EXPECT_EQ(size, s.size()); - EXPECT_LT(s.capacity(), size + 16); -} - -TEST(file, ReadFileToString_capacity_0) { - TemporaryFile tf; - ASSERT_NE(tf.fd, -1) << tf.path; - - // Because /proc reports its files as zero-length, we don't actually trust - // any file that claims to be zero-length. Rather than add increasingly - // complex heuristics for shrinking the passed-in string in that case, we - // currently leave it alone. - std::string s; - size_t initial_capacity = s.capacity(); - ASSERT_TRUE(android::base::WriteStringToFile("", tf.path)); - ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s)); - EXPECT_EQ(0U, s.size()); - EXPECT_EQ(initial_capacity, s.capacity()); -} diff --git a/base/format_benchmark.cpp b/base/format_benchmark.cpp deleted file mode 100644 index 9590b2365..000000000 --- a/base/format_benchmark.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/format.h" - -#include - -#include - -#include "android-base/stringprintf.h" - -using android::base::StringPrintf; - -static void BenchmarkFormatInt(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(fmt::format("{} {} {}", 42, std::numeric_limits::min(), - std::numeric_limits::max())); - } -} - -BENCHMARK(BenchmarkFormatInt); - -static void BenchmarkStringPrintfInt(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(StringPrintf("%d %d %d", 42, std::numeric_limits::min(), - std::numeric_limits::max())); - } -} - -BENCHMARK(BenchmarkStringPrintfInt); - -static void BenchmarkFormatFloat(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(fmt::format("{} {} {}", 42.42, std::numeric_limits::min(), - std::numeric_limits::max())); - } -} - -BENCHMARK(BenchmarkFormatFloat); - -static void BenchmarkStringPrintfFloat(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(StringPrintf("%f %f %f", 42.42, std::numeric_limits::min(), - std::numeric_limits::max())); - } -} - -BENCHMARK(BenchmarkStringPrintfFloat); - -static void BenchmarkFormatStrings(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(fmt::format("{} hello there {}", "hi,", "!!")); - } -} - -BENCHMARK(BenchmarkFormatStrings); - -static void BenchmarkStringPrintfStrings(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(StringPrintf("%s hello there %s", "hi,", "!!")); - } -} - -BENCHMARK(BenchmarkStringPrintfStrings); - -// Run the benchmark -BENCHMARK_MAIN(); diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h deleted file mode 100644 index 11fcf710e..000000000 --- a/base/include/android-base/chrono_utils.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include -#include - -#if __cplusplus > 201103L && !defined(__WIN32) // C++14 -using namespace std::chrono_literals; -#endif - -namespace android { -namespace base { - -// A std::chrono clock based on CLOCK_BOOTTIME. -class boot_clock { - public: - typedef std::chrono::nanoseconds duration; - typedef std::chrono::time_point time_point; - - static time_point now(); -}; - -class Timer { - public: - Timer() : start_(boot_clock::now()) {} - - std::chrono::milliseconds duration() const { - return std::chrono::duration_cast(boot_clock::now() - start_); - } - - private: - boot_clock::time_point start_; -}; - -std::ostream& operator<<(std::ostream& os, const Timer& t); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/cmsg.h b/base/include/android-base/cmsg.h deleted file mode 100644 index e4197b109..000000000 --- a/base/include/android-base/cmsg.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include -#include - -#include -#include -#include - -namespace android { -namespace base { - -#if !defined(_WIN32) - -// Helpers for sending and receiving file descriptors across Unix domain sockets. -// -// The cmsg(3) API is very hard to get right, with multiple landmines that can -// lead to death. Almost all of the uses of cmsg in Android make at least one of -// the following mistakes: -// -// - not aligning the cmsg buffer -// - leaking fds if more fds are received than expected -// - blindly dereferencing CMSG_DATA without checking the header -// - using CMSG_SPACE instead of CMSG_LEN for .cmsg_len -// - using CMSG_LEN instead of CMSG_SPACE for .msg_controllen -// - using a length specified in number of fds instead of bytes -// -// These functions wrap the hard-to-use cmsg API with an easier to use abstraction. - -// Send file descriptors across a Unix domain socket. -// -// Note that the write can return short if the socket type is SOCK_STREAM. When -// this happens, file descriptors are still sent to the other end, but with -// truncated data. For this reason, using SOCK_SEQPACKET or SOCK_DGRAM is recommended. -ssize_t SendFileDescriptorVector(borrowed_fd sock, const void* data, size_t len, - const std::vector& fds); - -// Receive file descriptors from a Unix domain socket. -// -// If more FDs (or bytes, for datagram sockets) are received than expected, -// -1 is returned with errno set to EMSGSIZE, and all received FDs are thrown away. -ssize_t ReceiveFileDescriptorVector(borrowed_fd sock, void* data, size_t len, size_t max_fds, - std::vector* fds); - -// Helper for SendFileDescriptorVector that constructs a std::vector for you, e.g.: -// SendFileDescriptors(sock, "foo", 3, std::move(fd1), std::move(fd2)) -template -ssize_t SendFileDescriptors(borrowed_fd sock, const void* data, size_t len, Args&&... sent_fds) { - // Do not allow implicit conversion to int: people might try to do something along the lines of: - // SendFileDescriptors(..., std::move(a_unique_fd)) - // and be surprised when the unique_fd isn't closed afterwards. - AssertType(std::forward(sent_fds)...); - std::vector fds; - Append(fds, std::forward(sent_fds)...); - return SendFileDescriptorVector(sock, data, len, fds); -} - -// Helper for ReceiveFileDescriptorVector that receives an exact number of file descriptors. -// If more file descriptors are received than requested, -1 is returned with errno set to EMSGSIZE. -// If fewer file descriptors are received than requested, -1 is returned with errno set to ENOMSG. -// In both cases, all arguments are cleared and any received FDs are thrown away. -template -ssize_t ReceiveFileDescriptors(borrowed_fd sock, void* data, size_t len, Args&&... received_fds) { - std::vector fds; - Append(fds, std::forward(received_fds)...); - - std::vector result; - ssize_t rc = ReceiveFileDescriptorVector(sock, data, len, fds.size(), &result); - if (rc == -1 || result.size() != fds.size()) { - int err = rc == -1 ? errno : ENOMSG; - for (unique_fd* fd : fds) { - fd->reset(); - } - errno = err; - return -1; - } - - for (size_t i = 0; i < fds.size(); ++i) { - *fds[i] = std::move(result[i]); - } - return rc; -} - -#endif - -} // namespace base -} // namespace android diff --git a/base/include/android-base/collections.h b/base/include/android-base/collections.h deleted file mode 100644 index be0683ab9..000000000 --- a/base/include/android-base/collections.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -namespace android { -namespace base { - -// Helpers for converting a variadic template parameter pack to a homogeneous collection. -// Parameters must be implictly convertible to the contained type (including via move/copy ctors). -// -// Use as follows: -// -// template -// std::vector CreateVector(Args&&... args) { -// std::vector result; -// Append(result, std::forward(args)...); -// return result; -// } -template -void Append(CollectionType& collection, T&& arg) { - collection.push_back(std::forward(arg)); -} - -template -void Append(CollectionType& collection, T&& arg, Args&&... args) { - collection.push_back(std::forward(arg)); - return Append(collection, std::forward(args)...); -} - -// Assert that all of the arguments in a variadic template parameter pack are of a given type -// after std::decay. -template -void AssertType(Arg&&) { - static_assert(std::is_same::type>::value); -} - -template -void AssertType(Arg&&, Args&&... args) { - static_assert(std::is_same::type>::value); - AssertType(std::forward(args)...); -} - -} // namespace base -} // namespace android diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h deleted file mode 100644 index 8fa6365ee..000000000 --- a/base/include/android-base/endian.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - */ - -#pragma once - -/* A cross-platform equivalent of bionic's . */ - -/* For __BIONIC__ and __GLIBC__ */ -#include - -#if defined(__BIONIC__) - -#include - -#elif defined(__GLIBC__) - -/* glibc's is like bionic's . */ -#include - -/* glibc keeps htons and htonl in . */ -#include - -/* glibc doesn't have the 64-bit variants. */ -#define htonq(x) htobe64(x) -#define ntohq(x) be64toh(x) - -/* glibc has different names to BSD for these. */ -#define betoh16(x) be16toh(x) -#define betoh32(x) be32toh(x) -#define betoh64(x) be64toh(x) -#define letoh16(x) le16toh(x) -#define letoh32(x) le32toh(x) -#define letoh64(x) le64toh(x) - -#else - -#if defined(__APPLE__) -/* macOS has some of the basics. */ -#include -#else -/* Windows has some of the basics as well. */ -#include -#include -/* winsock2.h *must* be included before the following four macros. */ -#define htons(x) __builtin_bswap16(x) -#define htonl(x) __builtin_bswap32(x) -#define ntohs(x) __builtin_bswap16(x) -#define ntohl(x) __builtin_bswap32(x) -#endif - -/* Neither macOS nor Windows have the rest. */ - -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __BYTE_ORDER __LITTLE_ENDIAN - -#define htonq(x) __builtin_bswap64(x) - -#define ntohq(x) __builtin_bswap64(x) - -#define htobe16(x) __builtin_bswap16(x) -#define htobe32(x) __builtin_bswap32(x) -#define htobe64(x) __builtin_bswap64(x) - -#define betoh16(x) __builtin_bswap16(x) -#define betoh32(x) __builtin_bswap32(x) -#define betoh64(x) __builtin_bswap64(x) - -#define htole16(x) (x) -#define htole32(x) (x) -#define htole64(x) (x) - -#define letoh16(x) (x) -#define letoh32(x) (x) -#define letoh64(x) (x) - -#define be16toh(x) __builtin_bswap16(x) -#define be32toh(x) __builtin_bswap32(x) -#define be64toh(x) __builtin_bswap64(x) - -#define le16toh(x) (x) -#define le32toh(x) (x) -#define le64toh(x) (x) - -#endif diff --git a/base/include/android-base/errno_restorer.h b/base/include/android-base/errno_restorer.h deleted file mode 100644 index 1c8597c96..000000000 --- a/base/include/android-base/errno_restorer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include "errno.h" - -#include "android-base/macros.h" - -namespace android { -namespace base { - -class ErrnoRestorer { - public: - ErrnoRestorer() : saved_errno_(errno) {} - - ~ErrnoRestorer() { errno = saved_errno_; } - - // Allow this object to be used as part of && operation. - operator bool() const { return true; } - - private: - const int saved_errno_; - - DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer); -}; - -} // namespace base -} // namespace android diff --git a/base/include/android-base/errors.h b/base/include/android-base/errors.h deleted file mode 100644 index 06f29fcac..000000000 --- a/base/include/android-base/errors.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -// Portable error handling functions. This is only necessary for host-side -// code that needs to be cross-platform; code that is only run on Unix should -// just use errno and strerror() for simplicity. -// -// There is some complexity since Windows has (at least) three different error -// numbers, not all of which share the same type: -// * errno: for C runtime errors. -// * GetLastError(): Windows non-socket errors. -// * WSAGetLastError(): Windows socket errors. -// errno can be passed to strerror() on all platforms, but the other two require -// special handling to get the error string. Refer to Microsoft documentation -// to determine which error code to check for each function. - -#pragma once - -#include - -namespace android { -namespace base { - -// Returns a string describing the given system error code. |error_code| must -// be errno on Unix or GetLastError()/WSAGetLastError() on Windows. Passing -// errno on Windows has undefined behavior. -std::string SystemErrorCodeToString(int error_code); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h deleted file mode 100644 index 9470344e8..000000000 --- a/base/include/android-base/expected.h +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include -#include -#include -#include - -// android::base::expected is an Android implementation of the std::expected -// proposal. -// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0323r7.html -// -// Usage: -// using android::base::expected; -// using android::base::unexpected; -// -// expected safe_divide(double i, double j) { -// if (j == 0) return unexpected("divide by zero"); -// else return i / j; -// } -// -// void test() { -// auto q = safe_divide(10, 0); -// if (q) { printf("%f\n", q.value()); } -// else { printf("%s\n", q.error().c_str()); } -// } -// -// When the proposal becomes part of the standard and is implemented by -// libcxx, this will be removed and android::base::expected will be -// type alias to std::expected. -// - -namespace android { -namespace base { - -// Synopsis -template - class expected; - -template - class unexpected; -template - unexpected(E) -> unexpected; - -template - class bad_expected_access; - -template<> - class bad_expected_access; - -struct unexpect_t { - explicit unexpect_t() = default; -}; -inline constexpr unexpect_t unexpect{}; - -// macros for SFINAE -#define _ENABLE_IF(...) \ - , std::enable_if_t<(__VA_ARGS__)>* = nullptr - -// Define NODISCARD_EXPECTED to prevent expected from being -// ignored when used as a return value. This is off by default. -#ifdef NODISCARD_EXPECTED -#define _NODISCARD_ [[nodiscard]] -#else -#define _NODISCARD_ -#endif - -// Class expected -template -class _NODISCARD_ expected { - public: - using value_type = T; - using error_type = E; - using unexpected_type = unexpected; - - template - using rebind = expected; - - // constructors - constexpr expected() = default; - constexpr expected(const expected& rhs) = default; - constexpr expected(expected&& rhs) noexcept = default; - - template && - std::is_constructible_v && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !(!std::is_convertible_v || - !std::is_convertible_v) /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(const expected& rhs) { - if (rhs.has_value()) var_ = rhs.value(); - else var_ = unexpected(rhs.error()); - } - - template && - std::is_constructible_v && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - (!std::is_convertible_v || - !std::is_convertible_v) /* explicit */ - )> - constexpr explicit expected(const expected& rhs) { - if (rhs.has_value()) var_ = rhs.value(); - else var_ = unexpected(rhs.error()); - } - - template && - std::is_constructible_v && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !(!std::is_convertible_v || - !std::is_convertible_v) /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(expected&& rhs) { - if (rhs.has_value()) var_ = std::move(rhs.value()); - else var_ = unexpected(std::move(rhs.error())); - } - - template && - std::is_constructible_v && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_constructible_v&> && - !std::is_constructible_v&&> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - !std::is_convertible_v&, T> && - !std::is_convertible_v&&, T> && - (!std::is_convertible_v || - !std::is_convertible_v) /* explicit */ - )> - constexpr explicit expected(expected&& rhs) { - if (rhs.has_value()) var_ = std::move(rhs.value()); - else var_ = unexpected(std::move(rhs.error())); - } - - template && - !std::is_same_v>, std::in_place_t> && - !std::is_same_v, std::remove_cv_t>> && - !std::is_same_v, std::remove_cv_t>> && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload) - constexpr expected(U&& v) : var_(std::in_place_index<0>, std::forward(v)) {} - - template && - !std::is_same_v>, std::in_place_t> && - !std::is_same_v, std::remove_cv_t>> && - !std::is_same_v, std::remove_cv_t>> && - !std::is_convertible_v /* explicit */ - )> - // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) - constexpr explicit expected(U&& v) : var_(std::in_place_index<0>, T(std::forward(v))) {} - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(const unexpected& e) - : var_(std::in_place_index<1>, e.value()) {} - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(const unexpected& e) - : var_(std::in_place_index<1>, E(e.value())) {} - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(unexpected&& e) - : var_(std::in_place_index<1>, std::move(e.value())) {} - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(unexpected&& e) - : var_(std::in_place_index<1>, E(std::move(e.value()))) {} - - template - )> - constexpr explicit expected(std::in_place_t, Args&&... args) - : var_(std::in_place_index<0>, std::forward(args)...) {} - - template&, Args...> - )> - constexpr explicit expected(std::in_place_t, std::initializer_list il, Args&&... args) - : var_(std::in_place_index<0>, il, std::forward(args)...) {} - - template - )> - constexpr explicit expected(unexpect_t, Args&&... args) - : var_(unexpected_type(std::forward(args)...)) {} - - template&, Args...> - )> - constexpr explicit expected(unexpect_t, std::initializer_list il, Args&&... args) - : var_(unexpected_type(il, std::forward(args)...)) {} - - // destructor - ~expected() = default; - - // assignment - // Note: SFNAIE doesn't work here because assignment operator should be - // non-template. We could workaround this by defining a templated parent class - // having the assignment operator. This incomplete implementation however - // doesn't allow us to copy assign expected even when T is non-copy - // assignable. The copy assignment will fail by the underlying std::variant - // anyway though the error message won't be clear. - expected& operator=(const expected& rhs) = default; - - // Note for SFNAIE above applies to here as well - expected& operator=(expected&& rhs) noexcept( - std::is_nothrow_move_assignable_v&& std::is_nothrow_move_assignable_v) = default; - - template && - !std::is_same_v, std::remove_cv_t>> && - !std::conjunction_v, std::is_same>> && - std::is_constructible_v && std::is_assignable_v && - std::is_nothrow_move_constructible_v)> - expected& operator=(U&& rhs) { - var_ = T(std::forward(rhs)); - return *this; - } - - template - expected& operator=(const unexpected& rhs) { - var_ = rhs; - return *this; - } - - template && - std::is_move_assignable_v - )> - expected& operator=(unexpected&& rhs) { - var_ = std::move(rhs); - return *this; - } - - // modifiers - template - )> - T& emplace(Args&&... args) { - expected(std::in_place, std::forward(args)...).swap(*this); - return value(); - } - - template&, Args...> - )> - T& emplace(std::initializer_list il, Args&&... args) { - expected(std::in_place, il, std::forward(args)...).swap(*this); - return value(); - } - - // swap - template && - std::is_swappable_v && - (std::is_move_constructible_v || - std::is_move_constructible_v))>> - void swap(expected& rhs) noexcept( - std::is_nothrow_move_constructible_v && - std::is_nothrow_swappable_v && - std::is_nothrow_move_constructible_v && - std::is_nothrow_swappable_v) { - var_.swap(rhs.var_); - } - - // observers - constexpr const T* operator->() const { return std::addressof(value()); } - constexpr T* operator->() { return std::addressof(value()); } - constexpr const T& operator*() const& { return value(); } - constexpr T& operator*() & { return value(); } - constexpr const T&& operator*() const&& { return std::move(std::get(var_)); } - constexpr T&& operator*() && { return std::move(std::get(var_)); } - - constexpr explicit operator bool() const noexcept { return has_value(); } - constexpr bool has_value() const noexcept { return var_.index() == 0; } - constexpr bool ok() const noexcept { return has_value(); } - - constexpr const T& value() const& { return std::get(var_); } - constexpr T& value() & { return std::get(var_); } - constexpr const T&& value() const&& { return std::move(std::get(var_)); } - constexpr T&& value() && { return std::move(std::get(var_)); } - - constexpr const E& error() const& { return std::get(var_).value(); } - constexpr E& error() & { return std::get(var_).value(); } - constexpr const E&& error() const&& { return std::move(std::get(var_)).value(); } - constexpr E&& error() && { return std::move(std::get(var_)).value(); } - - template && - std::is_convertible_v - )> - constexpr T value_or(U&& v) const& { - if (has_value()) return value(); - else return static_cast(std::forward(v)); - } - - template && - std::is_convertible_v - )> - constexpr T value_or(U&& v) && { - if (has_value()) return std::move(value()); - else return static_cast(std::forward(v)); - } - - // expected equality operators - template - friend constexpr bool operator==(const expected& x, const expected& y); - template - friend constexpr bool operator!=(const expected& x, const expected& y); - - // Comparison with unexpected - template - friend constexpr bool operator==(const expected&, const unexpected&); - template - friend constexpr bool operator==(const unexpected&, const expected&); - template - friend constexpr bool operator!=(const expected&, const unexpected&); - template - friend constexpr bool operator!=(const unexpected&, const expected&); - - // Specialized algorithms - template - friend void swap(expected&, expected&) noexcept; - - private: - std::variant var_; -}; - -template -constexpr bool operator==(const expected& x, const expected& y) { - if (x.has_value() != y.has_value()) return false; - if (!x.has_value()) return x.error() == y.error(); - return *x == *y; -} - -template -constexpr bool operator!=(const expected& x, const expected& y) { - return !(x == y); -} - -// Comparison with unexpected -template -constexpr bool operator==(const expected& x, const unexpected& y) { - return !x.has_value() && (x.error() == y.value()); -} -template -constexpr bool operator==(const unexpected& x, const expected& y) { - return !y.has_value() && (x.value() == y.error()); -} -template -constexpr bool operator!=(const expected& x, const unexpected& y) { - return x.has_value() || (x.error() != y.value()); -} -template -constexpr bool operator!=(const unexpected& x, const expected& y) { - return y.has_value() || (x.value() != y.error()); -} - -template -class _NODISCARD_ expected { - public: - using value_type = void; - using error_type = E; - using unexpected_type = unexpected; - - // constructors - constexpr expected() = default; - constexpr expected(const expected& rhs) = default; - constexpr expected(expected&& rhs) noexcept = default; - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(const expected& rhs) { - if (!rhs.has_value()) var_ = unexpected(rhs.error()); - } - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(const expected& rhs) { - if (!rhs.has_value()) var_ = unexpected(rhs.error()); - } - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(expected&& rhs) { - if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error())); - } - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(expected&& rhs) { - if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error())); - } - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(const unexpected& e) - : var_(std::in_place_index<1>, e.value()) {} - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(const unexpected& e) - : var_(std::in_place_index<1>, E(e.value())) {} - - template && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr expected(unexpected&& e) - : var_(std::in_place_index<1>, std::move(e.value())) {} - - template && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit expected(unexpected&& e) - : var_(std::in_place_index<1>, E(std::move(e.value()))) {} - - template - constexpr explicit expected(std::in_place_t, Args&&...) {} - - template - )> - constexpr explicit expected(unexpect_t, Args&&... args) - : var_(unexpected_type(std::forward(args)...)) {} - - template&, Args...> - )> - constexpr explicit expected(unexpect_t, std::initializer_list il, Args&&... args) - : var_(unexpected_type(il, std::forward(args)...)) {} - - // destructor - ~expected() = default; - - // assignment - // Note: SFNAIE doesn't work here because assignment operator should be - // non-template. We could workaround this by defining a templated parent class - // having the assignment operator. This incomplete implementation however - // doesn't allow us to copy assign expected even when T is non-copy - // assignable. The copy assignment will fail by the underlying std::variant - // anyway though the error message won't be clear. - expected& operator=(const expected& rhs) = default; - - // Note for SFNAIE above applies to here as well - expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v) = default; - - template - expected& operator=(const unexpected& rhs) { - var_ = rhs; - return *this; - } - - template && - std::is_move_assignable_v - )> - expected& operator=(unexpected&& rhs) { - var_ = std::move(rhs); - return *this; - } - - // modifiers - void emplace() { - var_ = std::monostate(); - } - - // swap - template> - > - void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v) { - var_.swap(rhs.var_); - } - - // observers - constexpr explicit operator bool() const noexcept { return has_value(); } - constexpr bool has_value() const noexcept { return var_.index() == 0; } - constexpr bool ok() const noexcept { return has_value(); } - - constexpr void value() const& { if (!has_value()) std::get<0>(var_); } - - constexpr const E& error() const& { return std::get(var_).value(); } - constexpr E& error() & { return std::get(var_).value(); } - constexpr const E&& error() const&& { return std::move(std::get(var_)).value(); } - constexpr E&& error() && { return std::move(std::get(var_)).value(); } - - // expected equality operators - template - friend constexpr bool operator==(const expected& x, const expected& y); - - // Specialized algorithms - template - friend void swap(expected&, expected&) noexcept; - - private: - std::variant var_; -}; - -template -constexpr bool operator==(const expected& x, const expected& y) { - if (x.has_value() != y.has_value()) return false; - if (!x.has_value()) return x.error() == y.error(); - return true; -} - -template -constexpr bool operator==(const expected& x, const expected& y) { - if (x.has_value() != y.has_value()) return false; - if (!x.has_value()) return x.error() == y.error(); - return false; -} - -template -constexpr bool operator==(const expected& x, const expected& y) { - if (x.has_value() != y.has_value()) return false; - if (!x.has_value()) return x.error() == y.error(); - return false; -} - -template -class unexpected { - public: - // constructors - constexpr unexpected(const unexpected&) = default; - constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v) = default; - - template && - !std::is_same_v>, std::in_place_t> && - !std::is_same_v>, unexpected>)> - // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload) - constexpr unexpected(Err&& e) : val_(std::forward(e)) {} - - template&, Args...> - )> - constexpr explicit unexpected(std::in_place_t, std::initializer_list il, Args&&... args) - : val_(il, std::forward(args)...) {} - - template && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr unexpected(const unexpected& rhs) - : val_(rhs.value()) {} - - template && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit unexpected(const unexpected& rhs) - : val_(E(rhs.value())) {} - - template && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - std::is_convertible_v /* non-explicit */ - )> - // NOLINTNEXTLINE(google-explicit-constructor) - constexpr unexpected(unexpected&& rhs) - : val_(std::move(rhs.value())) {} - - template && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_constructible_v&> && - !std::is_constructible_v> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v&, E> && - !std::is_convertible_v, E> && - !std::is_convertible_v /* explicit */ - )> - constexpr explicit unexpected(unexpected&& rhs) - : val_(E(std::move(rhs.value()))) {} - - // assignment - constexpr unexpected& operator=(const unexpected&) = default; - constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v) = - default; - template - constexpr unexpected& operator=(const unexpected& rhs) { - val_ = rhs.value(); - return *this; - } - template - constexpr unexpected& operator=(unexpected&& rhs) { - val_ = std::forward(rhs.value()); - return *this; - } - - // observer - constexpr const E& value() const& noexcept { return val_; } - constexpr E& value() & noexcept { return val_; } - constexpr const E&& value() const&& noexcept { return std::move(val_); } - constexpr E&& value() && noexcept { return std::move(val_); } - - void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v) { - std::swap(val_, other.val_); - } - - template - friend constexpr bool - operator==(const unexpected& e1, const unexpected& e2); - template - friend constexpr bool - operator!=(const unexpected& e1, const unexpected& e2); - - template - friend void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); - - private: - E val_; -}; - -template -constexpr bool -operator==(const unexpected& e1, const unexpected& e2) { - return e1.value() == e2.value(); -} - -template -constexpr bool -operator!=(const unexpected& e1, const unexpected& e2) { - return e1.value() != e2.value(); -} - -template -void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))) { - x.swap(y); -} - -// TODO: bad_expected_access class - -#undef _ENABLE_IF -#undef _NODISCARD_ - -} // namespace base -} // namespace android diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h deleted file mode 100644 index c62256277..000000000 --- a/base/include/android-base/file.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include - -#include - -#include "android-base/macros.h" -#include "android-base/off64_t.h" -#include "android-base/unique_fd.h" - -#if !defined(_WIN32) && !defined(O_BINARY) -/** Windows needs O_BINARY, but Unix never mangles line endings. */ -#define O_BINARY 0 -#endif - -#if defined(_WIN32) && !defined(O_CLOEXEC) -/** Windows has O_CLOEXEC but calls it O_NOINHERIT for some reason. */ -#define O_CLOEXEC O_NOINHERIT -#endif - -class TemporaryFile { - public: - TemporaryFile(); - explicit TemporaryFile(const std::string& tmp_dir); - ~TemporaryFile(); - - // Release the ownership of fd, caller is reponsible for closing the - // fd or stream properly. - int release(); - // Don't remove the temporary file in the destructor. - void DoNotRemove() { remove_file_ = false; } - - int fd; - char path[1024]; - - private: - void init(const std::string& tmp_dir); - - bool remove_file_ = true; - - DISALLOW_COPY_AND_ASSIGN(TemporaryFile); -}; - -class TemporaryDir { - public: - TemporaryDir(); - ~TemporaryDir(); - // Don't remove the temporary dir in the destructor. - void DoNotRemove() { remove_dir_and_contents_ = false; } - - char path[1024]; - - private: - bool init(const std::string& tmp_dir); - - bool remove_dir_and_contents_ = true; - - DISALLOW_COPY_AND_ASSIGN(TemporaryDir); -}; - -namespace android { -namespace base { - -bool ReadFdToString(borrowed_fd fd, std::string* content); -bool ReadFileToString(const std::string& path, std::string* content, - bool follow_symlinks = false); - -bool WriteStringToFile(const std::string& content, const std::string& path, - bool follow_symlinks = false); -bool WriteStringToFd(const std::string& content, borrowed_fd fd); - -#if !defined(_WIN32) -bool WriteStringToFile(const std::string& content, const std::string& path, - mode_t mode, uid_t owner, gid_t group, - bool follow_symlinks = false); -#endif - -bool ReadFully(borrowed_fd fd, void* data, size_t byte_count); - -// Reads `byte_count` bytes from the file descriptor at the specified offset. -// Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes. -// -// NOTE: On Linux/Mac, this function wraps pread, which provides atomic read support without -// modifying the read pointer of the file descriptor. On Windows, however, the read pointer does -// get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the -// same function, but concurrently seeking or reading incrementally can lead to unexpected -// behavior. -bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset); - -bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count); - -bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr); - -#if !defined(_WIN32) -bool Realpath(const std::string& path, std::string* result); -bool Readlink(const std::string& path, std::string* result); -#endif - -std::string GetExecutablePath(); -std::string GetExecutableDirectory(); - -// Like the regular basename and dirname, but thread-safe on all -// platforms and capable of correctly handling exotic Windows paths. -std::string Basename(const std::string& path); -std::string Dirname(const std::string& path); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/format.h b/base/include/android-base/format.h deleted file mode 100644 index 330040d8a..000000000 --- a/base/include/android-base/format.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -// We include fmtlib here as an alias, since libbase will have fmtlib statically linked already. -// It is accessed through its normal fmt:: namespace. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshadow" -#include -#pragma clang diagnostic pop -#include -#include -#include -#include diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h deleted file mode 100644 index 26827fb83..000000000 --- a/base/include/android-base/logging.h +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -// -// Google-style C++ logging. -// - -// This header provides a C++ stream interface to logging. -// -// To log: -// -// LOG(INFO) << "Some text; " << some_value; -// -// Replace `INFO` with any severity from `enum LogSeverity`. -// -// To log the result of a failed function and include the string -// representation of `errno` at the end: -// -// PLOG(ERROR) << "Write failed"; -// -// The output will be something like `Write failed: I/O error`. -// Remember this as 'P' as in perror(3). -// -// To output your own types, simply implement operator<< as normal. -// -// By default, output goes to logcat on Android and stderr on the host. -// A process can use `SetLogger` to decide where all logging goes. -// Implementations are provided for logcat, stderr, and dmesg. -// -// By default, the process' name is used as the log tag. -// Code can choose a specific log tag by defining LOG_TAG -// before including this header. - -// This header also provides assertions: -// -// CHECK(must_be_true); -// CHECK_EQ(a, b) << z_is_interesting_too; - -// NOTE: For Windows, you must include logging.h after windows.h to allow the -// following code to suppress the evil ERROR macro: -#ifdef _WIN32 -// windows.h includes wingdi.h which defines an evil macro ERROR. -#ifdef ERROR -#undef ERROR -#endif -#endif - -#include -#include -#include - -#include "android-base/errno_restorer.h" -#include "android-base/macros.h" - -// Note: DO NOT USE DIRECTLY. Use LOG_TAG instead. -#ifdef _LOG_TAG_INTERNAL -#error "_LOG_TAG_INTERNAL must not be defined" -#endif -#ifdef LOG_TAG -#define _LOG_TAG_INTERNAL LOG_TAG -#else -#define _LOG_TAG_INTERNAL nullptr -#endif - -namespace android { -namespace base { - -enum LogSeverity { - VERBOSE, - DEBUG, - INFO, - WARNING, - ERROR, - FATAL_WITHOUT_ABORT, // For loggability tests, this is considered identical to FATAL. - FATAL, -}; - -enum LogId { - DEFAULT, - MAIN, - SYSTEM, - RADIO, - CRASH, -}; - -using LogFunction = std::function; -using AbortFunction = std::function; - -// Loggers for use with InitLogging/SetLogger. - -// Log to the kernel log (dmesg). -void KernelLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*); -// Log to stderr in the full logcat format (with pid/tid/time/tag details). -void StderrLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*); -// Log just the message to stdout/stderr (without pid/tid/time/tag details). -// The choice of stdout versus stderr is based on the severity. -// Errors are also prefixed by the program name (as with err(3)/error(3)). -// Useful for replacing printf(3)/perror(3)/err(3)/error(3) in command-line tools. -void StdioLogger(LogId, LogSeverity, const char*, const char*, unsigned int, const char*); - -void DefaultAborter(const char* abort_message); - -void SetDefaultTag(const std::string& tag); - -// The LogdLogger sends chunks of up to ~4000 bytes at a time to logd. It does not prevent other -// threads from writing to logd between sending each chunk, so other threads may interleave their -// messages. If preventing interleaving is required, then a custom logger that takes a lock before -// calling this logger should be provided. -class LogdLogger { - public: - explicit LogdLogger(LogId default_log_id = android::base::MAIN); - - void operator()(LogId, LogSeverity, const char* tag, const char* file, - unsigned int line, const char* message); - - private: - LogId default_log_id_; -}; - -// Configure logging based on ANDROID_LOG_TAGS environment variable. -// We need to parse a string that looks like -// -// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i -// -// The tag (or '*' for the global level) comes first, followed by a colon and a -// letter indicating the minimum priority level we're expected to log. This can -// be used to reveal or conceal logs with specific tags. -#ifdef __ANDROID__ -#define INIT_LOGGING_DEFAULT_LOGGER LogdLogger() -#else -#define INIT_LOGGING_DEFAULT_LOGGER StderrLogger -#endif -void InitLogging(char* argv[], - LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER, - AbortFunction&& aborter = DefaultAborter); -#undef INIT_LOGGING_DEFAULT_LOGGER - -// Replace the current logger. -void SetLogger(LogFunction&& logger); - -// Replace the current aborter. -void SetAborter(AbortFunction&& aborter); - -// A helper macro that produces an expression that accepts both a qualified name and an -// unqualified name for a LogSeverity, and returns a LogSeverity value. -// Note: DO NOT USE DIRECTLY. This is an implementation detail. -#define SEVERITY_LAMBDA(severity) ([&]() { \ - using ::android::base::VERBOSE; \ - using ::android::base::DEBUG; \ - using ::android::base::INFO; \ - using ::android::base::WARNING; \ - using ::android::base::ERROR; \ - using ::android::base::FATAL_WITHOUT_ABORT; \ - using ::android::base::FATAL; \ - return (severity); }()) - -#ifdef __clang_analyzer__ -// Clang's static analyzer does not see the conditional statement inside -// LogMessage's destructor that will abort on FATAL severity. -#define ABORT_AFTER_LOG_FATAL for (;; abort()) - -struct LogAbortAfterFullExpr { - ~LogAbortAfterFullExpr() __attribute__((noreturn)) { abort(); } - explicit operator bool() const { return false; } -}; -// Provides an expression that evaluates to the truthiness of `x`, automatically -// aborting if `c` is true. -#define ABORT_AFTER_LOG_EXPR_IF(c, x) (((c) && ::android::base::LogAbortAfterFullExpr()) || (x)) -// Note to the static analyzer that we always execute FATAL logs in practice. -#define MUST_LOG_MESSAGE(severity) (SEVERITY_LAMBDA(severity) == ::android::base::FATAL) -#else -#define ABORT_AFTER_LOG_FATAL -#define ABORT_AFTER_LOG_EXPR_IF(c, x) (x) -#define MUST_LOG_MESSAGE(severity) false -#endif -#define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x) - -// Defines whether the given severity will be logged or silently swallowed. -#define WOULD_LOG(severity) \ - (UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \ - MUST_LOG_MESSAGE(severity)) - -// Get an ostream that can be used for logging at the given severity and to the default -// destination. -// -// Notes: -// 1) This will not check whether the severity is high enough. One should use WOULD_LOG to filter -// usage manually. -// 2) This does not save and restore errno. -#define LOG_STREAM(severity) \ - ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, \ - -1) \ - .stream() - -// Logs a message to logcat on Android otherwise to stderr. If the severity is -// FATAL it also causes an abort. For example: -// -// LOG(FATAL) << "We didn't expect to reach here"; -#define LOG(severity) LOGGING_PREAMBLE(severity) && LOG_STREAM(severity) - -// Checks if we want to log something, and sets up appropriate RAII objects if -// so. -// Note: DO NOT USE DIRECTLY. This is an implementation detail. -#define LOGGING_PREAMBLE(severity) \ - (WOULD_LOG(severity) && \ - ABORT_AFTER_LOG_EXPR_IF((SEVERITY_LAMBDA(severity)) == ::android::base::FATAL, true) && \ - ::android::base::ErrnoRestorer()) - -// A variant of LOG that also logs the current errno value. To be used when -// library calls fail. -#define PLOG(severity) \ - LOGGING_PREAMBLE(severity) && \ - ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), \ - _LOG_TAG_INTERNAL, errno) \ - .stream() - -// Marker that code is yet to be implemented. -#define UNIMPLEMENTED(level) \ - LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " - -// Check whether condition x holds and LOG(FATAL) if not. The value of the -// expression x is only evaluated once. Extra logging can be appended using << -// after. For example: -// -// CHECK(false == true) results in a log message of -// "Check failed: false == true". -#define CHECK(x) \ - LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, \ - -1) \ - .stream() \ - << "Check failed: " #x << " " - -// clang-format off -// Helper for CHECK_xx(x,y) macros. -#define CHECK_OP(LHS, RHS, OP) \ - for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \ - UNLIKELY(!(_values.lhs OP _values.rhs)); \ - /* empty */) \ - ABORT_AFTER_LOG_FATAL \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \ - .stream() \ - << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" << _values.lhs \ - << ", " #RHS "=" << _values.rhs << ") " -// clang-format on - -// Check whether a condition holds between x and y, LOG(FATAL) if not. The value -// of the expressions x and y is evaluated once. Extra logging can be appended -// using << after. For example: -// -// CHECK_NE(0 == 1, false) results in -// "Check failed: false != false (0==1=false, false=false) ". -#define CHECK_EQ(x, y) CHECK_OP(x, y, == ) -#define CHECK_NE(x, y) CHECK_OP(x, y, != ) -#define CHECK_LE(x, y) CHECK_OP(x, y, <= ) -#define CHECK_LT(x, y) CHECK_OP(x, y, < ) -#define CHECK_GE(x, y) CHECK_OP(x, y, >= ) -#define CHECK_GT(x, y) CHECK_OP(x, y, > ) - -// clang-format off -// Helper for CHECK_STRxx(s1,s2) macros. -#define CHECK_STROP(s1, s2, sense) \ - while (UNLIKELY((strcmp(s1, s2) == 0) != (sense))) \ - ABORT_AFTER_LOG_FATAL \ - ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, \ - _LOG_TAG_INTERNAL, -1) \ - .stream() \ - << "Check failed: " << "\"" << (s1) << "\"" \ - << ((sense) ? " == " : " != ") << "\"" << (s2) << "\"" -// clang-format on - -// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not. -#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) -#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) - -// Perform the pthread function call(args), LOG(FATAL) on error. -#define CHECK_PTHREAD_CALL(call, args, what) \ - do { \ - int rc = call args; \ - if (rc != 0) { \ - errno = rc; \ - ABORT_AFTER_LOG_FATAL \ - PLOG(FATAL) << #call << " failed for " << (what); \ - } \ - } while (false) - -// CHECK that can be used in a constexpr function. For example: -// -// constexpr int half(int n) { -// return -// DCHECK_CONSTEXPR(n >= 0, , 0) -// CHECK_CONSTEXPR((n & 1) == 0), -// << "Extra debugging output: n = " << n, 0) -// n / 2; -// } -#define CHECK_CONSTEXPR(x, out, dummy) \ - (UNLIKELY(!(x))) \ - ? (LOG(FATAL) << "Check failed: " << #x out, dummy) \ - : - -// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally -// CHECK should be used unless profiling identifies a CHECK as being in -// performance critical code. -#if defined(NDEBUG) && !defined(__clang_analyzer__) -static constexpr bool kEnableDChecks = false; -#else -static constexpr bool kEnableDChecks = true; -#endif - -#define DCHECK(x) \ - if (::android::base::kEnableDChecks) CHECK(x) -#define DCHECK_EQ(x, y) \ - if (::android::base::kEnableDChecks) CHECK_EQ(x, y) -#define DCHECK_NE(x, y) \ - if (::android::base::kEnableDChecks) CHECK_NE(x, y) -#define DCHECK_LE(x, y) \ - if (::android::base::kEnableDChecks) CHECK_LE(x, y) -#define DCHECK_LT(x, y) \ - if (::android::base::kEnableDChecks) CHECK_LT(x, y) -#define DCHECK_GE(x, y) \ - if (::android::base::kEnableDChecks) CHECK_GE(x, y) -#define DCHECK_GT(x, y) \ - if (::android::base::kEnableDChecks) CHECK_GT(x, y) -#define DCHECK_STREQ(s1, s2) \ - if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2) -#define DCHECK_STRNE(s1, s2) \ - if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2) -#if defined(NDEBUG) && !defined(__clang_analyzer__) -#define DCHECK_CONSTEXPR(x, out, dummy) -#else -#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy) -#endif - -// Temporary class created to evaluate the LHS and RHS, used with -// MakeEagerEvaluator to infer the types of LHS and RHS. -template -struct EagerEvaluator { - constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { - } - LHS lhs; - RHS rhs; -}; - -// Helper function for CHECK_xx. -template -constexpr EagerEvaluator MakeEagerEvaluator(LHS lhs, RHS rhs) { - return EagerEvaluator(lhs, rhs); -} - -// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated -// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on -// signed/unsigned warnings to protect you against combinations not explicitly -// listed below. -#define EAGER_PTR_EVALUATOR(T1, T2) \ - template <> \ - struct EagerEvaluator { \ - EagerEvaluator(T1 l, T2 r) \ - : lhs(reinterpret_cast(l)), \ - rhs(reinterpret_cast(r)) { \ - } \ - const void* lhs; \ - const void* rhs; \ - } -EAGER_PTR_EVALUATOR(const char*, const char*); -EAGER_PTR_EVALUATOR(const char*, char*); -EAGER_PTR_EVALUATOR(char*, const char*); -EAGER_PTR_EVALUATOR(char*, char*); -EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*); -EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*); -EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*); -EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*); -EAGER_PTR_EVALUATOR(const signed char*, const signed char*); -EAGER_PTR_EVALUATOR(const signed char*, signed char*); -EAGER_PTR_EVALUATOR(signed char*, const signed char*); -EAGER_PTR_EVALUATOR(signed char*, signed char*); - -// Data for the log message, not stored in LogMessage to avoid increasing the -// stack size. -class LogMessageData; - -// A LogMessage is a temporarily scoped object used by LOG and the unlikely part -// of a CHECK. The destructor will abort if the severity is FATAL. -class LogMessage { - public: - // LogId has been deprecated, but this constructor must exist for prebuilts. - LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag, - int error); - LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error); - - ~LogMessage(); - - // Returns the stream associated with the message, the LogMessage performs - // output when it goes out of scope. - std::ostream& stream(); - - // The routine that performs the actual logging. - static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, - const char* msg); - - private: - const std::unique_ptr data_; - - DISALLOW_COPY_AND_ASSIGN(LogMessage); -}; - -// Get the minimum severity level for logging. -LogSeverity GetMinimumLogSeverity(); - -// Set the minimum severity level for logging, returning the old severity. -LogSeverity SetMinimumLogSeverity(LogSeverity new_severity); - -// Return whether or not a log message with the associated tag should be logged. -bool ShouldLog(LogSeverity severity, const char* tag); - -// Allows to temporarily change the minimum severity level for logging. -class ScopedLogSeverity { - public: - explicit ScopedLogSeverity(LogSeverity level); - ~ScopedLogSeverity(); - - private: - LogSeverity old_; -}; - -} // namespace base -} // namespace android - -namespace std { // NOLINT(cert-dcl58-cpp) - -// Emit a warning of ostream<< with std::string*. The intention was most likely to print *string. -// -// Note: for this to work, we need to have this in a namespace. -// Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") complains about -// diagnose_if. -// Note: to print the pointer, use "<< static_cast(string_pointer)" instead. -// Note: a not-recommended alternative is to let Clang ignore the warning by adding -// -Wno-user-defined-warnings to CPPFLAGS. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wgcc-compat" -#define OSTREAM_STRING_POINTER_USAGE_WARNING \ - __attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning"))) -inline OSTREAM_STRING_POINTER_USAGE_WARNING -std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer) { - return stream << static_cast(string_pointer); -} -#pragma clang diagnostic pop - -} // namespace std diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h deleted file mode 100644 index 546b2ec18..000000000 --- a/base/include/android-base/macros.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include // for size_t -#include // for TEMP_FAILURE_RETRY - -#include - -// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't. -#ifndef TEMP_FAILURE_RETRY -#define TEMP_FAILURE_RETRY(exp) \ - ({ \ - decltype(exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; \ - }) -#endif - -// A macro to disallow the copy constructor and operator= functions -// This must be placed in the private: declarations for a class. -// -// For disallowing only assign or copy, delete the relevant operator or -// constructor, for example: -// void operator=(const TypeName&) = delete; -// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken -// semantically, one should either use disallow both or neither. Try to -// avoid these in new code. -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - void operator=(const TypeName&) = delete - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName() = delete; \ - DISALLOW_COPY_AND_ASSIGN(TypeName) - -// The arraysize(arr) macro returns the # of elements in an array arr. -// The expression is a compile-time constant, and therefore can be -// used in defining new arrays, for example. If you use arraysize on -// a pointer by mistake, you will get a compile-time error. -// -// One caveat is that arraysize() doesn't accept any array of an -// anonymous type or a type defined inside a function. In these rare -// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is -// due to a limitation in C++'s template system. The limitation might -// eventually be removed, but it hasn't happened yet. - -// This template function declaration is used in defining arraysize. -// Note that the function doesn't need an implementation, as we only -// use its type. -template -char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting) - -#define arraysize(array) (sizeof(ArraySizeHelper(array))) - -#define SIZEOF_MEMBER(t, f) sizeof(std::declval().f) - -// Changing this definition will cause you a lot of pain. A majority of -// vendor code defines LIKELY and UNLIKELY this way, and includes -// this header through an indirect path. -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -#define WARN_UNUSED __attribute__((warn_unused_result)) - -// A deprecated function to call to create a false use of the parameter, for -// example: -// int foo(int x) { UNUSED(x); return 10; } -// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED. -template -void UNUSED(const T&...) { -} - -// An attribute to place on a parameter to a function, for example: -// int foo(int x ATTRIBUTE_UNUSED) { return 10; } -// to avoid compiler warnings. -#define ATTRIBUTE_UNUSED __attribute__((__unused__)) - -// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through -// between switch labels: -// switch (x) { -// case 40: -// case 41: -// if (truth_is_out_there) { -// ++x; -// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in -// // comments. -// } else { -// return x; -// } -// case 42: -// ... -// -// As shown in the example above, the FALLTHROUGH_INTENDED macro should be -// followed by a semicolon. It is designed to mimic control-flow statements -// like 'break;', so it can be placed in most places where 'break;' can, but -// only if there are no statements on the execution path between it and the -// next switch label. -// -// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to -// [[clang::fallthrough]] attribute, which is analysed when performing switch -// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang -// documentation on language extensions for details: -// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough -// -// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no -// effect on diagnostics. -// -// In either case this macro has no effect on runtime behavior and performance -// of code. -#ifndef FALLTHROUGH_INTENDED -#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT -#endif - -// Current ABI string -#if defined(__arm__) -#define ABI_STRING "arm" -#elif defined(__aarch64__) -#define ABI_STRING "arm64" -#elif defined(__i386__) -#define ABI_STRING "x86" -#elif defined(__x86_64__) -#define ABI_STRING "x86_64" -#endif diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h deleted file mode 100644 index 8c37f4305..000000000 --- a/base/include/android-base/mapped_file.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -#include - -#include "android-base/macros.h" -#include "android-base/off64_t.h" -#include "android-base/unique_fd.h" - -#if defined(_WIN32) -#include -#define PROT_READ 1 -#define PROT_WRITE 2 -using os_handle = HANDLE; -#else -#include -using os_handle = int; -#endif - -namespace android { -namespace base { - -/** - * A region of a file mapped into memory (for grepping: also known as MmapFile or file mapping). - */ -class MappedFile { - public: - /** - * Creates a new mapping of the file pointed to by `fd`. Unlike the underlying OS primitives, - * `offset` does not need to be page-aligned. If `PROT_WRITE` is set in `prot`, the mapping - * will be writable, otherwise it will be read-only. Mappings are always `MAP_SHARED`. - */ - static std::unique_ptr FromFd(borrowed_fd fd, off64_t offset, size_t length, - int prot); - - /** - * Same thing, but using the raw OS file handle instead of a CRT wrapper. - */ - static std::unique_ptr FromOsHandle(os_handle h, off64_t offset, size_t length, - int prot); - - /** - * Removes the mapping. - */ - ~MappedFile(); - - /** - * Not copyable but movable. - */ - MappedFile(MappedFile&& other); - MappedFile& operator=(MappedFile&& other); - - char* data() const { return base_ + offset_; } - size_t size() const { return size_; } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile); - - void Close(); - - char* base_; - size_t size_; - - size_t offset_; - -#if defined(_WIN32) - MappedFile(char* base, size_t size, size_t offset, HANDLE handle) - : base_(base), size_(size), offset_(offset), handle_(handle) {} - HANDLE handle_; -#else - MappedFile(char* base, size_t size, size_t offset) : base_(base), size_(size), offset_(offset) {} -#endif -}; - -} // namespace base -} // namespace android diff --git a/base/include/android-base/memory.h b/base/include/android-base/memory.h deleted file mode 100644 index 0277a034e..000000000 --- a/base/include/android-base/memory.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -namespace android { -namespace base { - -// Use memcpy for access to unaligned data on targets with alignment -// restrictions. The compiler will generate appropriate code to access these -// structures without generating alignment exceptions. -template -static inline T get_unaligned(const void* address) { - T result; - memcpy(&result, address, sizeof(T)); - return result; -} - -template -static inline void put_unaligned(void* address, T v) { - memcpy(address, &v, sizeof(T)); -} - -} // namespace base -} // namespace android diff --git a/base/include/android-base/no_destructor.h b/base/include/android-base/no_destructor.h deleted file mode 100644 index ce0dc9f2a..000000000 --- a/base/include/android-base/no_destructor.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2019 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 "android-base/macros.h" - -namespace android { -namespace base { - -// A wrapper that makes it easy to create an object of type T with static -// storage duration that: -// - is only constructed on first access -// - never invokes the destructor -// in order to satisfy the styleguide ban on global constructors and -// destructors. -// -// Runtime constant example: -// const std::string& GetLineSeparator() { -// // Forwards to std::string(size_t, char, const Allocator&) constructor. -// static const base::NoDestructor s(5, '-'); -// return *s; -// } -// -// More complex initialization with a lambda: -// const std::string& GetSessionNonce() { -// static const base::NoDestructor nonce([] { -// std::string s(16); -// crypto::RandString(s.data(), s.size()); -// return s; -// }()); -// return *nonce; -// } -// -// NoDestructor stores the object inline, so it also avoids a pointer -// indirection and a malloc. Also note that since C++11 static local variable -// initialization is thread-safe and so is this pattern. Code should prefer to -// use NoDestructor over: -// - A function scoped static T* or T& that is dynamically initialized. -// - A global base::LazyInstance. -// -// Note that since the destructor is never run, this *will* leak memory if used -// as a stack or member variable. Furthermore, a NoDestructor should never -// have global scope as that may require a static initializer. -template -class NoDestructor { - public: - // Not constexpr; just write static constexpr T x = ...; if the value should - // be a constexpr. - template - explicit NoDestructor(Args&&... args) { - new (storage_) T(std::forward(args)...); - } - - // Allows copy and move construction of the contained type, to allow - // construction from an initializer list, e.g. for std::vector. - explicit NoDestructor(const T& x) { new (storage_) T(x); } - explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); } - - NoDestructor(const NoDestructor&) = delete; - NoDestructor& operator=(const NoDestructor&) = delete; - - ~NoDestructor() = default; - - const T& operator*() const { return *get(); } - T& operator*() { return *get(); } - - const T* operator->() const { return get(); } - T* operator->() { return get(); } - - const T* get() const { return reinterpret_cast(storage_); } - T* get() { return reinterpret_cast(storage_); } - - private: - alignas(T) char storage_[sizeof(T)]; -}; - -} // namespace base -} // namespace android diff --git a/base/include/android-base/off64_t.h b/base/include/android-base/off64_t.h deleted file mode 100644 index e6b71b81e..000000000 --- a/base/include/android-base/off64_t.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#if defined(__APPLE__) -/** Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */ -typedef off_t off64_t; -#endif diff --git a/base/include/android-base/parsebool.h b/base/include/android-base/parsebool.h deleted file mode 100644 index b2bd0217e..000000000 --- a/base/include/android-base/parsebool.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include - -namespace android { -namespace base { - -// Parse the given string as yes or no inactivation of some sort. Return one of the -// ParseBoolResult enumeration values. -// -// The following values parse as true: -// -// 1 -// on -// true -// y -// yes -// -// -// The following values parse as false: -// -// 0 -// false -// n -// no -// off -// -// Anything else is a parse error. -// -// The purpose of this function is to have a single canonical parser for yes-or-no indications -// throughout the system. - -enum class ParseBoolResult { - kError, - kFalse, - kTrue, -}; - -ParseBoolResult ParseBool(std::string_view s); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/parsedouble.h b/base/include/android-base/parsedouble.h deleted file mode 100644 index ccffba232..000000000 --- a/base/include/android-base/parsedouble.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include -#include - -#include -#include - -namespace android { -namespace base { - -// Parse floating value in the string 's' and sets 'out' to that value if it exists. -// Optionally allows the caller to define a 'min' and 'max' beyond which -// otherwise valid values will be rejected. Returns boolean success. -template -static inline bool ParseFloatingPoint(const char* s, T* out, T min, T max) { - errno = 0; - char* end; - T result = strtox(s, &end); - if (errno != 0 || s == end || *end != '\0') { - return false; - } - if (result < min || max < result) { - return false; - } - if (out != nullptr) { - *out = result; - } - return true; -} - -// Parse double value in the string 's' and sets 'out' to that value if it exists. -// Optionally allows the caller to define a 'min' and 'max' beyond which -// otherwise valid values will be rejected. Returns boolean success. -static inline bool ParseDouble(const char* s, double* out, - double min = std::numeric_limits::lowest(), - double max = std::numeric_limits::max()) { - return ParseFloatingPoint(s, out, min, max); -} -static inline bool ParseDouble(const std::string& s, double* out, - double min = std::numeric_limits::lowest(), - double max = std::numeric_limits::max()) { - return ParseFloatingPoint(s.c_str(), out, min, max); -} - -// Parse float value in the string 's' and sets 'out' to that value if it exists. -// Optionally allows the caller to define a 'min' and 'max' beyond which -// otherwise valid values will be rejected. Returns boolean success. -static inline bool ParseFloat(const char* s, float* out, - float min = std::numeric_limits::lowest(), - float max = std::numeric_limits::max()) { - return ParseFloatingPoint(s, out, min, max); -} -static inline bool ParseFloat(const std::string& s, float* out, - float min = std::numeric_limits::lowest(), - float max = std::numeric_limits::max()) { - return ParseFloatingPoint(s.c_str(), out, min, max); -} - -} // namespace base -} // namespace android diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h deleted file mode 100644 index be8b97b78..000000000 --- a/base/include/android-base/parseint.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace android { -namespace base { - -// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets -// 'out' to that value if it is specified. Optionally allows the caller to define -// a 'max' beyond which otherwise valid values will be rejected. Returns boolean -// success; 'out' is untouched if parsing fails. -template -bool ParseUint(const char* s, T* out, T max = std::numeric_limits::max(), - bool allow_suffixes = false) { - static_assert(std::is_unsigned::value, "ParseUint can only be used with unsigned types"); - while (isspace(*s)) { - s++; - } - - if (s[0] == '-') { - errno = EINVAL; - return false; - } - - int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; - errno = 0; - char* end; - unsigned long long int result = strtoull(s, &end, base); - if (errno != 0) return false; - if (end == s) { - errno = EINVAL; - return false; - } - if (*end != '\0') { - const char* suffixes = "bkmgtpe"; - const char* suffix; - if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) || - __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) { - errno = EINVAL; - return false; - } - } - if (max < result) { - errno = ERANGE; - return false; - } - if (out != nullptr) { - *out = static_cast(result); - } - return true; -} - -// TODO: string_view -template -bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits::max(), - bool allow_suffixes = false) { - return ParseUint(s.c_str(), out, max, allow_suffixes); -} - -template -bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits::max()) { - return ParseUint(s, out, max, true); -} - -// TODO: string_view -template -bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits::max()) { - return ParseByteCount(s.c_str(), out, max); -} - -// Parses the signed decimal or hexadecimal integer in the string 's' and sets -// 'out' to that value if it is specified. Optionally allows the caller to define -// a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns -// boolean success; 'out' is untouched if parsing fails. -template -bool ParseInt(const char* s, T* out, - T min = std::numeric_limits::min(), - T max = std::numeric_limits::max()) { - static_assert(std::is_signed::value, "ParseInt can only be used with signed types"); - while (isspace(*s)) { - s++; - } - - int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; - errno = 0; - char* end; - long long int result = strtoll(s, &end, base); - if (errno != 0) { - return false; - } - if (s == end || *end != '\0') { - errno = EINVAL; - return false; - } - if (result < min || max < result) { - errno = ERANGE; - return false; - } - if (out != nullptr) { - *out = static_cast(result); - } - return true; -} - -// TODO: string_view -template -bool ParseInt(const std::string& s, T* out, - T min = std::numeric_limits::min(), - T max = std::numeric_limits::max()) { - return ParseInt(s.c_str(), out, min, max); -} - -} // namespace base -} // namespace android diff --git a/base/include/android-base/parsenetaddress.h b/base/include/android-base/parsenetaddress.h deleted file mode 100644 index 47f8b5f6e..000000000 --- a/base/include/android-base/parsenetaddress.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include - -namespace android { -namespace base { - -// Parses |address| into |host| and |port|. -// -// If |address| doesn't contain a port number, the default value is taken from -// |port|. If |canonical_address| is non-null it will be set to "host:port" or -// "[host]:port" as appropriate. -// -// On failure, returns false and fills |error|. -bool ParseNetAddress(const std::string& address, std::string* host, int* port, - std::string* canonical_address, std::string* error); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/process.h b/base/include/android-base/process.h deleted file mode 100644 index 69ed3fba5..000000000 --- a/base/include/android-base/process.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -namespace android { -namespace base { - -class AllPids { - class PidIterator { - public: - PidIterator(DIR* dir) : dir_(dir, closedir) { Increment(); } - PidIterator& operator++() { - Increment(); - return *this; - } - bool operator==(const PidIterator& other) const { return pid_ == other.pid_; } - bool operator!=(const PidIterator& other) const { return !(*this == other); } - long operator*() const { return pid_; } - // iterator traits - using difference_type = pid_t; - using value_type = pid_t; - using pointer = const pid_t*; - using reference = const pid_t&; - using iterator_category = std::input_iterator_tag; - - private: - void Increment(); - - pid_t pid_ = -1; - std::unique_ptr dir_; - }; - - public: - PidIterator begin() { return opendir("/proc"); } - PidIterator end() { return nullptr; } -}; - -} // namespace base -} // namespace android diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h deleted file mode 100644 index 49f1f3184..000000000 --- a/base/include/android-base/properties.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -struct prop_info; - -namespace android { -namespace base { - -// Returns the current value of the system property `key`, -// or `default_value` if the property is empty or doesn't exist. -std::string GetProperty(const std::string& key, const std::string& default_value); - -// Returns true if the system property `key` has the value "1", "y", "yes", "on", or "true", -// false for "0", "n", "no", "off", or "false", or `default_value` otherwise. -bool GetBoolProperty(const std::string& key, bool default_value); - -// Returns the signed integer corresponding to the system property `key`. -// If the property is empty, doesn't exist, doesn't have an integer value, or is outside -// the optional bounds, returns `default_value`. -template T GetIntProperty(const std::string& key, - T default_value, - T min = std::numeric_limits::min(), - T max = std::numeric_limits::max()); - -// Returns the unsigned integer corresponding to the system property `key`. -// If the property is empty, doesn't exist, doesn't have an integer value, or is outside -// the optional bound, returns `default_value`. -template T GetUintProperty(const std::string& key, - T default_value, - T max = std::numeric_limits::max()); - -// Sets the system property `key` to `value`. -bool SetProperty(const std::string& key, const std::string& value); - -// Waits for the system property `key` to have the value `expected_value`. -// Times out after `relative_timeout`. -// Returns true on success, false on timeout. -#if defined(__BIONIC__) -bool WaitForProperty(const std::string& key, const std::string& expected_value, - std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max()); -#endif - -// Waits for the system property `key` to be created. -// Times out after `relative_timeout`. -// Returns true on success, false on timeout. -#if defined(__BIONIC__) -bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout = - std::chrono::milliseconds::max()); -#endif - -#if defined(__BIONIC__) && __cplusplus >= 201703L -// Cached system property lookup. For code that needs to read the same property multiple times, -// this class helps optimize those lookups. -class CachedProperty { - public: - explicit CachedProperty(const char* property_name); - - // Returns the current value of the underlying system property as cheaply as possible. - // The returned pointer is valid until the next call to Get. Because most callers are going - // to want to parse the string returned here and cached that as well, this function performs - // no locking, and is completely thread unsafe. It is the caller's responsibility to provide a - // lock for thread-safety. - // - // Note: *changed can be set to true even if the contents of the property remain the same. - const char* Get(bool* changed = nullptr); - - private: - std::string property_name_; - const prop_info* prop_info_; - std::optional cached_area_serial_; - std::optional cached_property_serial_; - char cached_value_[92]; - bool is_read_only_; - const char* read_only_property_; -}; -#endif - -} // namespace base -} // namespace android diff --git a/base/include/android-base/result.h b/base/include/android-base/result.h deleted file mode 100644 index 56a4f3e80..000000000 --- a/base/include/android-base/result.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * 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. - */ - -// This file contains classes for returning a successful result along with an optional -// arbitrarily typed return value or for returning a failure result along with an optional string -// indicating why the function failed. - -// There are 3 classes that implement this functionality and one additional helper type. -// -// Result either contains a member of type T that can be accessed using similar semantics as -// std::optional or it contains a ResultError describing an error, which can be accessed via -// Result::error(). -// -// ResultError is a type that contains both a std::string describing the error and a copy of errno -// from when the error occurred. ResultError can be used in an ostream directly to print its -// string value. -// -// Result is the correct return type for a function that either returns successfully or -// returns an error value. Returning {} from a function that returns Result is the -// correct way to indicate that a function without a return type has completed successfully. -// -// A successful Result is constructed implicitly from any type that can be implicitly converted -// to T or from the constructor arguments for T. This allows you to return a type T directly from -// a function that returns Result. -// -// Error and ErrnoError are used to construct a Result that has failed. The Error class takes -// an ostream as an input and are implicitly cast to a Result containing that failure. -// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno) -// to the end of the failure string to aid in interacting with C APIs. Alternatively, an errno -// value can be directly specified via the Error() constructor. -// -// Errorf and ErrnoErrorf accept the format string syntax of the fmblib (https://fmt.dev). -// Errorf("{} errors", num) is equivalent to Error() << num << " errors". -// -// ResultError can be used in the ostream and when using Error/Errorf to construct a Result. -// In this case, the string that the ResultError takes is passed through the stream normally, but -// the errno is passed to the Result. This can be used to pass errno from a failing C function up -// multiple callers. Note that when the outer Result is created with ErrnoError/ErrnoErrorf then -// the errno from the inner ResultError is not passed. Also when multiple ResultError objects are -// used, the errno of the last one is respected. -// -// ResultError can also directly construct a Result. This is particularly useful if you have a -// function that return Result but you have a Result and want to return its error. In this -// case, you can return the .error() from the Result to construct the Result. - -// An example of how to use these is below: -// Result CalculateResult(const T& input) { -// U output; -// if (!SomeOtherCppFunction(input, &output)) { -// return Errorf("SomeOtherCppFunction {} failed", input); -// } -// if (!c_api_function(output)) { -// return ErrnoErrorf("c_api_function {} failed", output); -// } -// return output; -// } -// -// auto output = CalculateResult(input); -// if (!output) return Error() << "CalculateResult failed: " << output.error(); -// UseOutput(*output); - -#pragma once - -#include - -#include -#include - -#include "android-base/expected.h" -#include "android-base/format.h" - -namespace android { -namespace base { - -struct ResultError { - template - ResultError(T&& message, int code) : message_(std::forward(message)), code_(code) {} - - template - // NOLINTNEXTLINE(google-explicit-constructor) - operator android::base::expected() { - return android::base::unexpected(ResultError(message_, code_)); - } - - std::string message() const { return message_; } - int code() const { return code_; } - - private: - std::string message_; - int code_; -}; - -inline bool operator==(const ResultError& lhs, const ResultError& rhs) { - return lhs.message() == rhs.message() && lhs.code() == rhs.code(); -} - -inline bool operator!=(const ResultError& lhs, const ResultError& rhs) { - return !(lhs == rhs); -} - -inline std::ostream& operator<<(std::ostream& os, const ResultError& t) { - os << t.message(); - return os; -} - -class Error { - public: - Error() : errno_(0), append_errno_(false) {} - // NOLINTNEXTLINE(google-explicit-constructor) - Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {} - - template - // NOLINTNEXTLINE(google-explicit-constructor) - operator android::base::expected() { - return android::base::unexpected(ResultError(str(), errno_)); - } - - template - Error& operator<<(T&& t) { - // NOLINTNEXTLINE(bugprone-suspicious-semicolon) - if constexpr (std::is_same_v>, ResultError>) { - errno_ = t.code(); - return (*this) << t.message(); - } - int saved = errno; - ss_ << t; - errno = saved; - return *this; - } - - const std::string str() const { - std::string str = ss_.str(); - if (append_errno_) { - if (str.empty()) { - return strerror(errno_); - } - return std::move(str) + ": " + strerror(errno_); - } - return str; - } - - Error(const Error&) = delete; - Error(Error&&) = delete; - Error& operator=(const Error&) = delete; - Error& operator=(Error&&) = delete; - - template - friend Error ErrorfImpl(const T&& fmt, const Args&... args); - - template - friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args); - - private: - Error(bool append_errno, int errno_to_append, const std::string& message) - : errno_(errno_to_append), append_errno_(append_errno) { - (*this) << message; - } - - std::stringstream ss_; - int errno_; - const bool append_errno_; -}; - -inline Error ErrnoError() { - return Error(errno); -} - -inline int ErrorCode(int code) { - return code; -} - -// Return the error code of the last ResultError object, if any. -// Otherwise, return `code` as it is. -template -inline int ErrorCode(int code, T&& t, const Args&... args) { - if constexpr (std::is_same_v>, ResultError>) { - return ErrorCode(t.code(), args...); - } - return ErrorCode(code, args...); -} - -template -inline Error ErrorfImpl(const T&& fmt, const Args&... args) { - return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...)); -} - -template -inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) { - return Error(true, errno, fmt::format(fmt, args...)); -} - -#define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) -#define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__) - -template -using Result = android::base::expected; - -// Macros for testing the results of functions that return android::base::Result. -// These also work with base::android::expected. - -#define CHECK_RESULT_OK(stmt) \ - do { \ - const auto& tmp = (stmt); \ - CHECK(tmp.ok()) << tmp.error(); \ - } while (0) - -#define ASSERT_RESULT_OK(stmt) \ - do { \ - const auto& tmp = (stmt); \ - ASSERT_TRUE(tmp.ok()) << tmp.error(); \ - } while (0) - -#define EXPECT_RESULT_OK(stmt) \ - do { \ - auto tmp = (stmt); \ - EXPECT_TRUE(tmp.ok()) << tmp.error(); \ - } while (0) - -// TODO: Maybe add RETURN_IF_ERROR() and ASSIGN_OR_RETURN() - -} // namespace base -} // namespace android diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h deleted file mode 100644 index 5a224d634..000000000 --- a/base/include/android-base/scopeguard.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -#pragma once - -#include // for std::move, std::forward - -namespace android { -namespace base { - -// ScopeGuard ensures that the specified functor is executed no matter how the -// current scope exits. -template -class ScopeGuard { - public: - ScopeGuard(F&& f) : f_(std::forward(f)), active_(true) {} - - ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) { - that.active_ = false; - } - - template - ScopeGuard(ScopeGuard&& that) : f_(std::move(that.f_)), active_(that.active_) { - that.active_ = false; - } - - ~ScopeGuard() { - if (active_) f_(); - } - - ScopeGuard() = delete; - ScopeGuard(const ScopeGuard&) = delete; - void operator=(const ScopeGuard&) = delete; - void operator=(ScopeGuard&& that) = delete; - - void Disable() { active_ = false; } - - bool active() const { return active_; } - - private: - template - friend class ScopeGuard; - - F f_; - bool active_; -}; - -template -ScopeGuard make_scope_guard(F&& f) { - return ScopeGuard(std::forward(f)); -} - -} // namespace base -} // namespace android diff --git a/base/include/android-base/stringprintf.h b/base/include/android-base/stringprintf.h deleted file mode 100644 index 93c56afd7..000000000 --- a/base/include/android-base/stringprintf.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#pragma once - -#include -#include - -namespace android { -namespace base { - -// These printf-like functions are implemented in terms of vsnprintf, so they -// use the same attribute for compile-time format string checking. - -// Returns a string corresponding to printf-like formatting of the arguments. -std::string StringPrintf(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))); - -// Appends a printf-like formatting of the arguments to 'dst'. -void StringAppendF(std::string* dst, const char* fmt, ...) - __attribute__((__format__(__printf__, 2, 3))); - -// Appends a printf-like formatting of the arguments to 'dst'. -void StringAppendV(std::string* dst, const char* format, va_list ap) - __attribute__((__format__(__printf__, 2, 0))); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h deleted file mode 100644 index 14d534a3b..000000000 --- a/base/include/android-base/strings.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include -#include -#include - -namespace android { -namespace base { - -// Splits a string into a vector of strings. -// -// The string is split at each occurrence of a character in delimiters. -// -// The empty string is not a valid delimiter list. -std::vector Split(const std::string& s, - const std::string& delimiters); - -// Trims whitespace off both ends of the given string. -std::string Trim(const std::string& s); - -// Joins a container of things into a single string, using the given separator. -template -std::string Join(const ContainerT& things, SeparatorT separator) { - if (things.empty()) { - return ""; - } - - std::ostringstream result; - result << *things.begin(); - for (auto it = std::next(things.begin()); it != things.end(); ++it) { - result << separator << *it; - } - return result.str(); -} - -// We instantiate the common cases in strings.cpp. -extern template std::string Join(const std::vector&, char); -extern template std::string Join(const std::vector&, char); -extern template std::string Join(const std::vector&, const std::string&); -extern template std::string Join(const std::vector&, const std::string&); - -// Tests whether 's' starts with 'prefix'. -bool StartsWith(std::string_view s, std::string_view prefix); -bool StartsWith(std::string_view s, char prefix); -bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix); - -// Tests whether 's' ends with 'suffix'. -bool EndsWith(std::string_view s, std::string_view suffix); -bool EndsWith(std::string_view s, char suffix); -bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix); - -// Tests whether 'lhs' equals 'rhs', ignoring case. -bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs); - -// Removes `prefix` from the start of the given string and returns true (if -// it was present), false otherwise. -inline bool ConsumePrefix(std::string_view* s, std::string_view prefix) { - if (!StartsWith(*s, prefix)) return false; - s->remove_prefix(prefix.size()); - return true; -} - -// Removes `suffix` from the end of the given string and returns true (if -// it was present), false otherwise. -inline bool ConsumeSuffix(std::string_view* s, std::string_view suffix) { - if (!EndsWith(*s, suffix)) return false; - s->remove_suffix(suffix.size()); - return true; -} - -// Replaces `from` with `to` in `s`, once if `all == false`, or as many times as -// there are matches if `all == true`. -[[nodiscard]] std::string StringReplace(std::string_view s, std::string_view from, - std::string_view to, bool all); - -} // namespace base -} // namespace android diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h deleted file mode 100644 index f3d7cb031..000000000 --- a/base/include/android-base/test_utils.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include - -#include -#include - -class CapturedStdFd { - public: - CapturedStdFd(int std_fd); - ~CapturedStdFd(); - - std::string str(); - - void Start(); - void Stop(); - void Reset(); - - private: - int fd() const; - - TemporaryFile temp_file_; - int std_fd_; - int old_fd_ = -1; - - DISALLOW_COPY_AND_ASSIGN(CapturedStdFd); -}; - -class CapturedStderr : public CapturedStdFd { - public: - CapturedStderr() : CapturedStdFd(STDERR_FILENO) {} -}; - -class CapturedStdout : public CapturedStdFd { - public: - CapturedStdout() : CapturedStdFd(STDOUT_FILENO) {} -}; - -#define ASSERT_MATCH(str, pattern) \ - do { \ - auto __s = (str); \ - if (!std::regex_search(__s, std::regex((pattern)))) { \ - FAIL() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \ - } \ - } while (0) - -#define ASSERT_NOT_MATCH(str, pattern) \ - do { \ - auto __s = (str); \ - if (std::regex_search(__s, std::regex((pattern)))) { \ - FAIL() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \ - } \ - } while (0) - -#define EXPECT_MATCH(str, pattern) \ - do { \ - auto __s = (str); \ - if (!std::regex_search(__s, std::regex((pattern)))) { \ - ADD_FAILURE() << "regex mismatch: expected " << (pattern) << " in:\n" << __s; \ - } \ - } while (0) - -#define EXPECT_NOT_MATCH(str, pattern) \ - do { \ - auto __s = (str); \ - if (std::regex_search(__s, std::regex((pattern)))) { \ - ADD_FAILURE() << "regex mismatch: expected to not find " << (pattern) << " in:\n" << __s; \ - } \ - } while (0) diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h deleted file mode 100644 index 53fe6dae9..000000000 --- a/base/include/android-base/thread_annotations.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -#pragma once - -#include - -#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) - -#define CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) - -#define SCOPED_CAPABILITY \ - THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) - -#define SHARED_CAPABILITY(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_capability(__VA_ARGS__)) - -#define GUARDED_BY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) - -#define PT_GUARDED_BY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) - -#define EXCLUSIVE_LOCKS_REQUIRED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) - -#define SHARED_LOCKS_REQUIRED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) - -#define ACQUIRED_BEFORE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) - -#define ACQUIRED_AFTER(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) - -#define REQUIRES(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) - -#define REQUIRES_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) - -#define ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) - -#define ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) - -#define RELEASE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) - -#define RELEASE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) - -#define EXCLUDES(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) - -#define ASSERT_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) - -#define ASSERT_SHARED_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) - -#define RETURN_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) - -#define EXCLUSIVE_LOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) - -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) - -#define SHARED_LOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) - -#define SHARED_TRYLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) - -#define UNLOCK_FUNCTION(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) - -#define SCOPED_LOCKABLE \ - THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) - -#define LOCK_RETURNED(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) - -#define NO_THREAD_SAFETY_ANALYSIS \ - THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) - -namespace android { -namespace base { - -// A class to help thread safety analysis deal with std::unique_lock and condition_variable. -// -// Clang's thread safety analysis currently doesn't perform alias analysis, so movable types -// like std::unique_lock can't be marked with thread safety annotations. This helper allows -// for manual assertion of lock state in a scope. -// -// For example: -// -// std::mutex mutex; -// std::condition_variable cv; -// std::vector vec GUARDED_BY(mutex); -// -// int pop() { -// std::unique_lock lock(mutex); -// ScopedLockAssertion lock_assertion(mutex); -// cv.wait(lock, []() { -// ScopedLockAssertion lock_assertion(mutex); -// return !vec.empty(); -// }); -// -// int result = vec.back(); -// vec.pop_back(); -// return result; -// } -class SCOPED_CAPABILITY ScopedLockAssertion { - public: - ScopedLockAssertion(std::mutex& mutex) ACQUIRE(mutex) {} - ~ScopedLockAssertion() RELEASE() {} -}; - -} // namespace base -} // namespace android diff --git a/base/include/android-base/threads.h b/base/include/android-base/threads.h deleted file mode 100644 index dba1fc620..000000000 --- a/base/include/android-base/threads.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#pragma once - -#include - -namespace android { -namespace base { -uint64_t GetThreadId(); -} -} // namespace android - -#if defined(__GLIBC__) -// bionic has this Linux-specifix call, but glibc doesn't. -extern "C" int tgkill(int tgid, int tid, int sig); -#endif diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h deleted file mode 100644 index 9ceb5dbdc..000000000 --- a/base/include/android-base/unique_fd.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#include -#include -#include - -#if !defined(_WIN32) -#include -#endif - -#include -#include -#include - -// DO NOT INCLUDE OTHER LIBBASE HEADERS! -// This file gets used in libbinder, and libbinder is used everywhere. -// Including other headers from libbase frequently results in inclusion of -// android-base/macros.h, which causes macro collisions. - -// 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. - -#if defined(__BIONIC__) -#include -#endif - -namespace android { -namespace base { - -struct DefaultCloser { -#if defined(__BIONIC__) - static void Tag(int fd, void* old_addr, void* new_addr) { - if (android_fdsan_exchange_owner_tag) { - uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD, - reinterpret_cast(old_addr)); - uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD, - reinterpret_cast(new_addr)); - android_fdsan_exchange_owner_tag(fd, old_tag, new_tag); - } - } - static void Close(int fd, void* addr) { - if (android_fdsan_close_with_tag) { - uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD, - reinterpret_cast(addr)); - android_fdsan_close_with_tag(fd, tag); - } else { - close(fd); - } - } -#else - static void Close(int fd) { - // 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(fd); - } -#endif -}; - -template -class unique_fd_impl final { - public: - unique_fd_impl() {} - - explicit unique_fd_impl(int fd) { reset(fd); } - ~unique_fd_impl() { reset(); } - - unique_fd_impl(const unique_fd_impl&) = delete; - void operator=(const unique_fd_impl&) = delete; - unique_fd_impl(unique_fd_impl&& other) noexcept { reset(other.release()); } - unique_fd_impl& operator=(unique_fd_impl&& s) noexcept { - int fd = s.fd_; - s.fd_ = -1; - reset(fd, &s); - return *this; - } - - [[clang::reinitializes]] void reset(int new_value = -1) { reset(new_value, nullptr); } - - int get() const { return fd_; } - -#if !defined(ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION) - // unique_fd's operator int is dangerous, but we have way too much code that - // depends on it, so make this opt-in at first. - operator int() const { return get(); } // NOLINT -#endif - - bool operator>=(int rhs) const { return get() >= rhs; } - bool operator<(int rhs) const { return get() < rhs; } - bool operator==(int rhs) const { return get() == rhs; } - bool operator!=(int rhs) const { return get() != rhs; } - bool operator==(const unique_fd_impl& rhs) const { return get() == rhs.get(); } - bool operator!=(const unique_fd_impl& rhs) const { return get() != rhs.get(); } - - // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1"). - bool operator!() const = delete; - - bool ok() const { return get() >= 0; } - - int release() __attribute__((warn_unused_result)) { - tag(fd_, this, nullptr); - int ret = fd_; - fd_ = -1; - return ret; - } - - private: - void reset(int new_value, void* previous_tag) { - int previous_errno = errno; - - if (fd_ != -1) { - close(fd_, this); - } - - fd_ = new_value; - if (new_value != -1) { - tag(new_value, previous_tag, this); - } - - errno = previous_errno; - } - - int fd_ = -1; - - // Template magic to use Closer::Tag if available, and do nothing if not. - // If Closer::Tag exists, this implementation is preferred, because int is a better match. - // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists. - template - static auto tag(int fd, void* old_tag, void* new_tag) - -> decltype(T::Tag(fd, old_tag, new_tag), void()) { - T::Tag(fd, old_tag, new_tag); - } - - template - static void tag(long, void*, void*) { - // No-op. - } - - // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*). - template - static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) { - T::Close(fd, tag_value); - } - - template - static auto close(int fd, void*) -> decltype(T::Close(fd), void()) { - T::Close(fd); - } -}; - -using unique_fd = unique_fd_impl; - -#if !defined(_WIN32) - -// Inline functions, so that they can be used header-only. -template -inline bool Pipe(unique_fd_impl* read, unique_fd_impl* write, - int flags = O_CLOEXEC) { - int pipefd[2]; - -#if defined(__linux__) - if (pipe2(pipefd, flags) != 0) { - return false; - } -#else // defined(__APPLE__) - if (flags & ~(O_CLOEXEC | O_NONBLOCK)) { - return false; - } - if (pipe(pipefd) != 0) { - return false; - } - - if (flags & O_CLOEXEC) { - if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) { - close(pipefd[0]); - close(pipefd[1]); - return false; - } - } - if (flags & O_NONBLOCK) { - if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 || fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) { - close(pipefd[0]); - close(pipefd[1]); - return false; - } - } -#endif - - read->reset(pipefd[0]); - write->reset(pipefd[1]); - return true; -} - -template -inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl* left, - unique_fd_impl* right) { - int sockfd[2]; - if (socketpair(domain, type, protocol, sockfd) != 0) { - return false; - } - left->reset(sockfd[0]); - right->reset(sockfd[1]); - return true; -} - -template -inline bool Socketpair(int type, unique_fd_impl* left, unique_fd_impl* right) { - return Socketpair(AF_UNIX, type, 0, left, right); -} - -// Using fdopen with unique_fd correctly is more annoying than it should be, -// because fdopen doesn't close the file descriptor received upon failure. -inline FILE* Fdopen(unique_fd&& ufd, const char* mode) { - int fd = ufd.release(); - FILE* file = fdopen(fd, mode); - if (!file) { - close(fd); - } - return file; -} - -// Using fdopendir with unique_fd correctly is more annoying than it should be, -// because fdopen doesn't close the file descriptor received upon failure. -inline DIR* Fdopendir(unique_fd&& ufd) { - int fd = ufd.release(); - DIR* dir = fdopendir(fd); - if (dir == nullptr) { - close(fd); - } - return dir; -} - -#endif // !defined(_WIN32) - -// A wrapper type that can be implicitly constructed from either int or unique_fd. -struct borrowed_fd { - /* implicit */ borrowed_fd(int fd) : fd_(fd) {} // NOLINT - template - /* implicit */ borrowed_fd(const unique_fd_impl& ufd) : fd_(ufd.get()) {} // NOLINT - - int get() const { return fd_; } - - bool operator>=(int rhs) const { return get() >= rhs; } - bool operator<(int rhs) const { return get() < rhs; } - bool operator==(int rhs) const { return get() == rhs; } - bool operator!=(int rhs) const { return get() != rhs; } - - private: - int fd_ = -1; -}; -} // namespace base -} // namespace android - -template -int close(const android::base::unique_fd_impl&) - __attribute__((__unavailable__("close called on unique_fd"))); - -template -FILE* fdopen(const android::base::unique_fd_impl&, const char* mode) - __attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the " - "unique_fd, or use android::base::Fdopen to pass ownership"))); - -template -DIR* fdopendir(const android::base::unique_fd_impl&) __attribute__(( - __unavailable__("fdopendir takes ownership of the fd passed in; either dup the " - "unique_fd, or use android::base::Fdopendir to pass ownership"))); diff --git a/base/include/android-base/utf8.h b/base/include/android-base/utf8.h deleted file mode 100644 index 1a414ec79..000000000 --- a/base/include/android-base/utf8.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#pragma once - -#ifdef _WIN32 -#include -#include -#else -// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace. -#include // open -#include // fopen -#include // mkdir -#include // unlink -#endif - -namespace android { -namespace base { - -// Only available on Windows because this is only needed on Windows. -#ifdef _WIN32 -// Convert size number of UTF-16 wchar_t's to UTF-8. Returns whether the -// conversion was done successfully. -bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8); - -// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Returns -// whether the conversion was done successfully. -bool WideToUTF8(const wchar_t* utf16, std::string* utf8); - -// Convert a UTF-16 std::wstring (including any embedded NULL characters) to -// UTF-8. Returns whether the conversion was done successfully. -bool WideToUTF8(const std::wstring& utf16, std::string* utf8); - -// Convert size number of UTF-8 char's to UTF-16. Returns whether the conversion -// was done successfully. -bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16); - -// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Returns -// whether the conversion was done successfully. -bool UTF8ToWide(const char* utf8, std::wstring* utf16); - -// Convert a UTF-8 std::string (including any embedded NULL characters) to -// UTF-16. Returns whether the conversion was done successfully. -bool UTF8ToWide(const std::string& utf8, std::wstring* utf16); - -// Convert a file system path, represented as a NULL-terminated string of -// UTF-8 characters, to a UTF-16 string representing the same file system -// path using the Windows extended-lengh path representation. -// -// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#MAXPATH: -// ```The Windows API has many functions that also have Unicode versions to -// permit an extended-length path for a maximum total path length of 32,767 -// characters. To specify an extended-length path, use the "\\?\" prefix. -// For example, "\\?\D:\very long path".``` -// -// Returns whether the conversion was done successfully. -bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16); -#endif - -// The functions in the utf8 namespace take UTF-8 strings. For Windows, these -// are wrappers, for non-Windows these just expose existing APIs. To call these -// functions, use: -// -// // anonymous namespace to avoid conflict with existing open(), unlink(), etc. -// namespace { -// // Import functions into anonymous namespace. -// using namespace android::base::utf8; -// -// void SomeFunction(const char* name) { -// int fd = open(name, ...); // Calls android::base::utf8::open(). -// ... -// unlink(name); // Calls android::base::utf8::unlink(). -// } -// } -namespace utf8 { - -#ifdef _WIN32 -FILE* fopen(const char* name, const char* mode); -int mkdir(const char* name, mode_t mode); -int open(const char* name, int flags, ...); -int unlink(const char* name); -#else -using ::fopen; -using ::mkdir; -using ::open; -using ::unlink; -#endif - -} // namespace utf8 -} // namespace base -} // namespace android diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp deleted file mode 100644 index 1f4b69b53..000000000 --- a/base/liblog_symbols.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2020 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 "liblog_symbols.h" - -#if defined(__ANDROID_SDK_VERSION__) && (__ANDROID_SDK_VERSION__ <= 29) -#define USE_DLSYM -#endif - -#ifdef USE_DLSYM -#include -#endif - -namespace android { -namespace base { - -#ifdef USE_DLSYM - -const std::optional& GetLibLogFunctions() { - static std::optional liblog_functions = []() -> std::optional { - void* liblog_handle = dlopen("liblog.so", RTLD_NOW); - if (liblog_handle == nullptr) { - return {}; - } - - LibLogFunctions real_liblog_functions = {}; - -#define DLSYM(name) \ - real_liblog_functions.name = \ - reinterpret_cast(dlsym(liblog_handle, #name)); \ - if (real_liblog_functions.name == nullptr) { \ - return {}; \ - } - - DLSYM(__android_log_set_logger) - DLSYM(__android_log_write_log_message) - DLSYM(__android_log_logd_logger) - DLSYM(__android_log_stderr_logger) - DLSYM(__android_log_set_aborter) - DLSYM(__android_log_call_aborter) - DLSYM(__android_log_default_aborter) - DLSYM(__android_log_set_minimum_priority); - DLSYM(__android_log_get_minimum_priority); - DLSYM(__android_log_set_default_tag); -#undef DLSYM - - return real_liblog_functions; - }(); - - return liblog_functions; -} - -#else - -const std::optional& GetLibLogFunctions() { - static std::optional liblog_functions = []() -> std::optional { - return LibLogFunctions{ - .__android_log_set_logger = __android_log_set_logger, - .__android_log_write_log_message = __android_log_write_log_message, - .__android_log_logd_logger = __android_log_logd_logger, - .__android_log_stderr_logger = __android_log_stderr_logger, - .__android_log_set_aborter = __android_log_set_aborter, - .__android_log_call_aborter = __android_log_call_aborter, - .__android_log_default_aborter = __android_log_default_aborter, - .__android_log_set_minimum_priority = __android_log_set_minimum_priority, - .__android_log_get_minimum_priority = __android_log_get_minimum_priority, - .__android_log_set_default_tag = __android_log_set_default_tag, - }; - }(); - return liblog_functions; -} - -#endif - -} // namespace base -} // namespace android diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h deleted file mode 100644 index 2e6b47f7d..000000000 --- a/base/liblog_symbols.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include - -#include - -namespace android { -namespace base { - -struct LibLogFunctions { - void (*__android_log_set_logger)(__android_logger_function logger); - void (*__android_log_write_log_message)(struct __android_log_message* log_message); - - void (*__android_log_logd_logger)(const struct __android_log_message* log_message); - void (*__android_log_stderr_logger)(const struct __android_log_message* log_message); - - void (*__android_log_set_aborter)(__android_aborter_function aborter); - void (*__android_log_call_aborter)(const char* abort_message); - void (*__android_log_default_aborter)(const char* abort_message); - int32_t (*__android_log_set_minimum_priority)(int32_t priority); - int32_t (*__android_log_get_minimum_priority)(); - void (*__android_log_set_default_tag)(const char* tag); -}; - -const std::optional& GetLibLogFunctions(); - -} // namespace base -} // namespace android diff --git a/base/logging.cpp b/base/logging.cpp deleted file mode 100644 index 5bd21da66..000000000 --- a/base/logging.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#if defined(_WIN32) -#include -#endif - -#include "android-base/logging.h" - -#include -#include -#include -#include - -// For getprogname(3) or program_invocation_short_name. -#if defined(__ANDROID__) || defined(__APPLE__) -#include -#elif defined(__GLIBC__) -#include -#endif - -#if defined(__linux__) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef __ANDROID__ -#include -#else -#include -#include -#endif - -#include -#include -#include -#include -#include - -#include "liblog_symbols.h" -#include "logging_splitters.h" - -namespace android { -namespace base { - -// BSD-based systems like Android/macOS have getprogname(). Others need us to provide one. -#if defined(__GLIBC__) || defined(_WIN32) -static const char* getprogname() { -#if defined(__GLIBC__) - return program_invocation_short_name; -#elif defined(_WIN32) - static bool first = true; - static char progname[MAX_PATH] = {}; - - if (first) { - snprintf(progname, sizeof(progname), "%s", - android::base::Basename(android::base::GetExecutablePath()).c_str()); - first = false; - } - - return progname; -#endif -} -#endif - -static const char* GetFileBasename(const char* file) { - // We can't use basename(3) even on Unix because the Mac doesn't - // have a non-modifying basename. - const char* last_slash = strrchr(file, '/'); - if (last_slash != nullptr) { - return last_slash + 1; - } -#if defined(_WIN32) - const char* last_backslash = strrchr(file, '\\'); - if (last_backslash != nullptr) { - return last_backslash + 1; - } -#endif - return file; -} - -#if defined(__linux__) -static int OpenKmsg() { -#if defined(__ANDROID__) - // pick up 'file w /dev/kmsg' environment from daemon's init rc file - const auto val = getenv("ANDROID_FILE__dev_kmsg"); - if (val != nullptr) { - int fd; - if (android::base::ParseInt(val, &fd, 0)) { - auto flags = fcntl(fd, F_GETFL); - if ((flags != -1) && ((flags & O_ACCMODE) == O_WRONLY)) return fd; - } - } -#endif - return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC)); -} -#endif - -static LogId log_id_tToLogId(int32_t buffer_id) { - switch (buffer_id) { - case LOG_ID_MAIN: - return MAIN; - case LOG_ID_SYSTEM: - return SYSTEM; - case LOG_ID_RADIO: - return RADIO; - case LOG_ID_CRASH: - return CRASH; - case LOG_ID_DEFAULT: - default: - return DEFAULT; - } -} - -static int32_t LogIdTolog_id_t(LogId log_id) { - switch (log_id) { - case MAIN: - return LOG_ID_MAIN; - case SYSTEM: - return LOG_ID_SYSTEM; - case RADIO: - return LOG_ID_RADIO; - case CRASH: - return LOG_ID_CRASH; - case DEFAULT: - default: - return LOG_ID_DEFAULT; - } -} - -static LogSeverity PriorityToLogSeverity(int priority) { - switch (priority) { - case ANDROID_LOG_DEFAULT: - return INFO; - case ANDROID_LOG_VERBOSE: - return VERBOSE; - case ANDROID_LOG_DEBUG: - return DEBUG; - case ANDROID_LOG_INFO: - return INFO; - case ANDROID_LOG_WARN: - return WARNING; - case ANDROID_LOG_ERROR: - return ERROR; - case ANDROID_LOG_FATAL: - return FATAL; - default: - return FATAL; - } -} - -static int32_t LogSeverityToPriority(LogSeverity severity) { - switch (severity) { - case VERBOSE: - return ANDROID_LOG_VERBOSE; - case DEBUG: - return ANDROID_LOG_DEBUG; - case INFO: - return ANDROID_LOG_INFO; - case WARNING: - return ANDROID_LOG_WARN; - case ERROR: - return ANDROID_LOG_ERROR; - case FATAL_WITHOUT_ABORT: - case FATAL: - default: - return ANDROID_LOG_FATAL; - } -} - -static LogFunction& Logger() { -#ifdef __ANDROID__ - static auto& logger = *new LogFunction(LogdLogger()); -#else - static auto& logger = *new LogFunction(StderrLogger); -#endif - return logger; -} - -static AbortFunction& Aborter() { - static auto& aborter = *new AbortFunction(DefaultAborter); - return aborter; -} - -// Only used for Q fallback. -static std::recursive_mutex& TagLock() { - static auto& tag_lock = *new std::recursive_mutex(); - return tag_lock; -} -// Only used for Q fallback. -static std::string* gDefaultTag; - -void SetDefaultTag(const std::string& tag) { - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - liblog_functions->__android_log_set_default_tag(tag.c_str()); - } else { - std::lock_guard lock(TagLock()); - if (gDefaultTag != nullptr) { - delete gDefaultTag; - gDefaultTag = nullptr; - } - if (!tag.empty()) { - gDefaultTag = new std::string(tag); - } - } -} - -static bool gInitialized = false; - -// Only used for Q fallback. -static LogSeverity gMinimumLogSeverity = INFO; - -#if defined(__linux__) -static void KernelLogLine(const char* msg, int length, android::base::LogSeverity severity, - const char* tag) { - // clang-format off - static constexpr int kLogSeverityToKernelLogLevel[] = { - [android::base::VERBOSE] = 7, // KERN_DEBUG (there is no verbose kernel log - // level) - [android::base::DEBUG] = 7, // KERN_DEBUG - [android::base::INFO] = 6, // KERN_INFO - [android::base::WARNING] = 4, // KERN_WARNING - [android::base::ERROR] = 3, // KERN_ERROR - [android::base::FATAL_WITHOUT_ABORT] = 2, // KERN_CRIT - [android::base::FATAL] = 2, // KERN_CRIT - }; - // clang-format on - static_assert(arraysize(kLogSeverityToKernelLogLevel) == android::base::FATAL + 1, - "Mismatch in size of kLogSeverityToKernelLogLevel and values in LogSeverity"); - - static int klog_fd = OpenKmsg(); - if (klog_fd == -1) return; - - int level = kLogSeverityToKernelLogLevel[severity]; - - // The kernel's printk buffer is only 1024 bytes. - // TODO: should we automatically break up long lines into multiple lines? - // Or we could log but with something like "..." at the end? - char buf[1024] __attribute__((__uninitialized__)); - size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %.*s\n", level, tag, length, msg); - if (size > sizeof(buf)) { - size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n", - level, tag, size); - } - - iovec iov[1]; - iov[0].iov_base = buf; - iov[0].iov_len = size; - TEMP_FAILURE_RETRY(writev(klog_fd, iov, 1)); -} - -void KernelLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag, - const char*, unsigned int, const char* full_message) { - SplitByLines(full_message, KernelLogLine, severity, tag); -} -#endif - -void StderrLogger(LogId, LogSeverity severity, const char* tag, const char* file, unsigned int line, - const char* message) { - struct tm now; - time_t t = time(nullptr); - -#if defined(_WIN32) - localtime_s(&now, &t); -#else - localtime_r(&t, &now); -#endif - auto output_string = - StderrOutputGenerator(now, getpid(), GetThreadId(), severity, tag, file, line, message); - - fputs(output_string.c_str(), stderr); -} - -void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/, - unsigned int /*line*/, const char* message) { - if (severity >= WARNING) { - fflush(stdout); - fprintf(stderr, "%s: %s\n", GetFileBasename(getprogname()), message); - } else { - fprintf(stdout, "%s\n", message); - } -} - -void DefaultAborter(const char* abort_message) { -#ifdef __ANDROID__ - android_set_abort_message(abort_message); -#else - UNUSED(abort_message); -#endif - abort(); -} - -static void LogdLogChunk(LogId id, LogSeverity severity, const char* tag, const char* message) { - int32_t lg_id = LogIdTolog_id_t(id); - int32_t priority = LogSeverityToPriority(severity); - - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - __android_log_message log_message = {sizeof(__android_log_message), lg_id, priority, tag, - static_cast(nullptr), 0, message}; - liblog_functions->__android_log_logd_logger(&log_message); - } else { - __android_log_buf_print(lg_id, priority, tag, "%s", message); - } -} - -LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {} - -void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, const char* file, - unsigned int line, const char* message) { - if (id == DEFAULT) { - id = default_log_id_; - } - - SplitByLogdChunks(id, severity, tag, file, line, message, LogdLogChunk); -} - -void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) { - SetLogger(std::forward(logger)); - SetAborter(std::forward(aborter)); - - if (gInitialized) { - return; - } - - gInitialized = true; - - // Stash the command line for later use. We can use /proc/self/cmdline on - // Linux to recover this, but we don't have that luxury on the Mac/Windows, - // and there are a couple of argv[0] variants that are commonly used. - if (argv != nullptr) { - SetDefaultTag(basename(argv[0])); - } - - const char* tags = getenv("ANDROID_LOG_TAGS"); - if (tags == nullptr) { - return; - } - - std::vector specs = Split(tags, " "); - for (size_t i = 0; i < specs.size(); ++i) { - // "tag-pattern:[vdiwefs]" - std::string spec(specs[i]); - if (spec.size() == 3 && StartsWith(spec, "*:")) { - switch (spec[2]) { - case 'v': - SetMinimumLogSeverity(VERBOSE); - continue; - case 'd': - SetMinimumLogSeverity(DEBUG); - continue; - case 'i': - SetMinimumLogSeverity(INFO); - continue; - case 'w': - SetMinimumLogSeverity(WARNING); - continue; - case 'e': - SetMinimumLogSeverity(ERROR); - continue; - case 'f': - SetMinimumLogSeverity(FATAL_WITHOUT_ABORT); - continue; - // liblog will even suppress FATAL if you say 's' for silent, but that's - // crazy! - case 's': - SetMinimumLogSeverity(FATAL_WITHOUT_ABORT); - continue; - } - } - LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags - << ")"; - } -} - -void SetLogger(LogFunction&& logger) { - Logger() = std::move(logger); - - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - liblog_functions->__android_log_set_logger([](const struct __android_log_message* log_message) { - auto log_id = log_id_tToLogId(log_message->buffer_id); - auto severity = PriorityToLogSeverity(log_message->priority); - - Logger()(log_id, severity, log_message->tag, log_message->file, log_message->line, - log_message->message); - }); - } -} - -void SetAborter(AbortFunction&& aborter) { - Aborter() = std::move(aborter); - - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - liblog_functions->__android_log_set_aborter( - [](const char* abort_message) { Aborter()(abort_message); }); - } -} - -// This indirection greatly reduces the stack impact of having lots of -// checks/logging in a function. -class LogMessageData { - public: - LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag, - int error) - : file_(GetFileBasename(file)), - line_number_(line), - severity_(severity), - tag_(tag), - error_(error) {} - - const char* GetFile() const { - return file_; - } - - unsigned int GetLineNumber() const { - return line_number_; - } - - LogSeverity GetSeverity() const { - return severity_; - } - - const char* GetTag() const { return tag_; } - - int GetError() const { - return error_; - } - - std::ostream& GetBuffer() { - return buffer_; - } - - std::string ToString() const { - return buffer_.str(); - } - - private: - std::ostringstream buffer_; - const char* const file_; - const unsigned int line_number_; - const LogSeverity severity_; - const char* const tag_; - const int error_; - - DISALLOW_COPY_AND_ASSIGN(LogMessageData); -}; - -LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, - const char* tag, int error) - : LogMessage(file, line, severity, tag, error) {} - -LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, - int error) - : data_(new LogMessageData(file, line, severity, tag, error)) {} - -LogMessage::~LogMessage() { - // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM. - if (!WOULD_LOG(data_->GetSeverity())) { - return; - } - - // Finish constructing the message. - if (data_->GetError() != -1) { - data_->GetBuffer() << ": " << strerror(data_->GetError()); - } - std::string msg(data_->ToString()); - - if (data_->GetSeverity() == FATAL) { -#ifdef __ANDROID__ - // Set the bionic abort message early to avoid liblog doing it - // with the individual lines, so that we get the whole message. - android_set_abort_message(msg.c_str()); -#endif - } - - LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(), - msg.c_str()); - - // Abort if necessary. - if (data_->GetSeverity() == FATAL) { - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - liblog_functions->__android_log_call_aborter(msg.c_str()); - } else { - Aborter()(msg.c_str()); - } - } -} - -std::ostream& LogMessage::stream() { - return data_->GetBuffer(); -} - -void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, - const char* message) { - static auto& liblog_functions = GetLibLogFunctions(); - int32_t priority = LogSeverityToPriority(severity); - if (liblog_functions) { - __android_log_message log_message = { - sizeof(__android_log_message), LOG_ID_DEFAULT, priority, tag, file, line, message}; - liblog_functions->__android_log_write_log_message(&log_message); - } else { - if (tag == nullptr) { - std::lock_guard lock(TagLock()); - if (gDefaultTag == nullptr) { - gDefaultTag = new std::string(getprogname()); - } - - Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message); - } else { - Logger()(DEFAULT, severity, tag, file, line, message); - } - } -} - -LogSeverity GetMinimumLogSeverity() { - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority()); - } else { - return gMinimumLogSeverity; - } -} - -bool ShouldLog(LogSeverity severity, const char* tag) { - static auto& liblog_functions = GetLibLogFunctions(); - // Even though we're not using the R liblog functions in this function, if we're running on Q, - // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not - // take into consideration the value from SetMinimumLogSeverity(). - if (liblog_functions) { - int32_t priority = LogSeverityToPriority(severity); - return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO); - } else { - return severity >= gMinimumLogSeverity; - } -} - -LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) { - static auto& liblog_functions = GetLibLogFunctions(); - if (liblog_functions) { - int32_t priority = LogSeverityToPriority(new_severity); - return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority)); - } else { - LogSeverity old_severity = gMinimumLogSeverity; - gMinimumLogSeverity = new_severity; - return old_severity; - } -} - -ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) { - old_ = SetMinimumLogSeverity(new_severity); -} - -ScopedLogSeverity::~ScopedLogSeverity() { - SetMinimumLogSeverity(old_); -} - -} // namespace base -} // namespace android diff --git a/base/logging_splitters.h b/base/logging_splitters.h deleted file mode 100644 index 2ec2b205d..000000000 --- a/base/logging_splitters.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -#pragma once - -#include - -#include -#include - -#define LOGGER_ENTRY_MAX_PAYLOAD 4068 // This constant is not in the NDK. - -namespace android { -namespace base { - -// This splits the message up line by line, by calling log_function with a pointer to the start of -// each line and the size up to the newline character. It sends size = -1 for the final line. -template -static void SplitByLines(const char* msg, const F& log_function, Args&&... args) { - const char* newline = strchr(msg, '\n'); - while (newline != nullptr) { - log_function(msg, newline - msg, args...); - msg = newline + 1; - newline = strchr(msg, '\n'); - } - - log_function(msg, -1, args...); -} - -// This splits the message up into chunks that logs can process delimited by new lines. It calls -// log_function with the exact null terminated message that should be sent to logd. -// Note, despite the loops and snprintf's, if severity is not fatal and there are no new lines, -// this function simply calls log_function with msg without any extra overhead. -template -static void SplitByLogdChunks(LogId log_id, LogSeverity severity, const char* tag, const char* file, - unsigned int line, const char* msg, const F& log_function) { - // The maximum size of a payload, after the log header that logd will accept is - // LOGGER_ENTRY_MAX_PAYLOAD, so subtract the other elements in the payload to find the size of - // the string that we can log in each pass. - // The protocol is documented in liblog/README.protocol.md. - // Specifically we subtract a byte for the priority, the length of the tag + its null terminator, - // and an additional byte for the null terminator on the payload. We subtract an additional 32 - // bytes for slack, similar to java/android/util/Log.java. - ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - strlen(tag) - 35; - if (max_size <= 0) { - abort(); - } - // If we're logging a fatal message, we'll append the file and line numbers. - bool add_file = file != nullptr && (severity == FATAL || severity == FATAL_WITHOUT_ABORT); - - std::string file_header; - if (add_file) { - file_header = StringPrintf("%s:%u] ", file, line); - } - int file_header_size = file_header.size(); - - __attribute__((uninitialized)) char logd_chunk[max_size + 1]; - ptrdiff_t chunk_position = 0; - - auto call_log_function = [&]() { - log_function(log_id, severity, tag, logd_chunk); - chunk_position = 0; - }; - - auto write_to_logd_chunk = [&](const char* message, int length) { - int size_written = 0; - const char* new_line = chunk_position > 0 ? "\n" : ""; - if (add_file) { - size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position, - "%s%s%.*s", new_line, file_header.c_str(), length, message); - } else { - size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position, - "%s%.*s", new_line, length, message); - } - - // This should never fail, if it does and we set size_written to 0, which will skip this line - // and move to the next one. - if (size_written < 0) { - size_written = 0; - } - chunk_position += size_written; - }; - - const char* newline = strchr(msg, '\n'); - while (newline != nullptr) { - // If we have data in the buffer and this next line doesn't fit, write the buffer. - if (chunk_position != 0 && chunk_position + (newline - msg) + 1 + file_header_size > max_size) { - call_log_function(); - } - - // Otherwise, either the next line fits or we have any empty buffer and too large of a line to - // ever fit, in both cases, we add it to the buffer and continue. - write_to_logd_chunk(msg, newline - msg); - - msg = newline + 1; - newline = strchr(msg, '\n'); - } - - // If we have left over data in the buffer and we can fit the rest of msg, add it to the buffer - // then write the buffer. - if (chunk_position != 0 && - chunk_position + static_cast(strlen(msg)) + 1 + file_header_size <= max_size) { - write_to_logd_chunk(msg, -1); - call_log_function(); - } else { - // If the buffer is not empty and we can't fit the rest of msg into it, write its contents. - if (chunk_position != 0) { - call_log_function(); - } - // Then write the rest of the msg. - if (add_file) { - snprintf(logd_chunk, sizeof(logd_chunk), "%s%s", file_header.c_str(), msg); - log_function(log_id, severity, tag, logd_chunk); - } else { - log_function(log_id, severity, tag, msg); - } - } -} - -static std::pair CountSizeAndNewLines(const char* message) { - int size = 0; - int new_lines = 0; - while (*message != '\0') { - size++; - if (*message == '\n') { - ++new_lines; - } - ++message; - } - return {size, new_lines}; -} - -// This adds the log header to each line of message and returns it as a string intended to be -// written to stderr. -static std::string StderrOutputGenerator(const struct tm& now, int pid, uint64_t tid, - LogSeverity severity, const char* tag, const char* file, - unsigned int line, const char* message) { - char timestamp[32]; - strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now); - - static const char log_characters[] = "VDIWEFF"; - static_assert(arraysize(log_characters) - 1 == FATAL + 1, - "Mismatch in size of log_characters and values in LogSeverity"); - char severity_char = log_characters[severity]; - std::string line_prefix; - if (file != nullptr) { - line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " %s:%u] ", tag ? tag : "nullptr", - severity_char, timestamp, pid, tid, file, line); - } else { - line_prefix = StringPrintf("%s %c %s %5d %5" PRIu64 " ", tag ? tag : "nullptr", severity_char, - timestamp, pid, tid); - } - - auto [size, new_lines] = CountSizeAndNewLines(message); - std::string output_string; - output_string.reserve(size + new_lines * line_prefix.size() + 1); - - auto concat_lines = [&](const char* message, int size) { - output_string.append(line_prefix); - if (size == -1) { - output_string.append(message); - } else { - output_string.append(message, size); - } - output_string.append("\n"); - }; - SplitByLines(message, concat_lines); - return output_string; -} - -} // namespace base -} // namespace android diff --git a/base/logging_splitters_test.cpp b/base/logging_splitters_test.cpp deleted file mode 100644 index 679d19ed1..000000000 --- a/base/logging_splitters_test.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2020 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 "logging_splitters.h" - -#include -#include - -#include -#include - -namespace android { -namespace base { - -void TestNewlineSplitter(const std::string& input, - const std::vector& expected_output) { - std::vector output; - auto logger_function = [&](const char* msg, int length) { - if (length == -1) { - output.push_back(msg); - } else { - output.push_back(std::string(msg, length)); - } - }; - SplitByLines(input.c_str(), logger_function); - - EXPECT_EQ(expected_output, output); -} - -TEST(logging_splitters, NewlineSplitter_EmptyString) { - TestNewlineSplitter("", std::vector{""}); -} - -TEST(logging_splitters, NewlineSplitter_BasicString) { - TestNewlineSplitter("normal string", std::vector{"normal string"}); -} - -TEST(logging_splitters, NewlineSplitter_ormalBasicStringTrailingNewline) { - TestNewlineSplitter("normal string\n", std::vector{"normal string", ""}); -} - -TEST(logging_splitters, NewlineSplitter_MultilineTrailing) { - TestNewlineSplitter("normal string\nsecond string\nthirdstring", - std::vector{"normal string", "second string", "thirdstring"}); -} - -TEST(logging_splitters, NewlineSplitter_MultilineTrailingNewline) { - TestNewlineSplitter( - "normal string\nsecond string\nthirdstring\n", - std::vector{"normal string", "second string", "thirdstring", ""}); -} - -TEST(logging_splitters, NewlineSplitter_MultilineEmbeddedNewlines) { - TestNewlineSplitter( - "normal string\n\n\nsecond string\n\nthirdstring\n", - std::vector{"normal string", "", "", "second string", "", "thirdstring", ""}); -} - -void TestLogdChunkSplitter(const std::string& tag, const std::string& file, - const std::string& input, - const std::vector& expected_output) { - std::vector output; - auto logger_function = [&](LogId, LogSeverity, const char*, const char* msg) { - output.push_back(msg); - }; - - SplitByLogdChunks(MAIN, FATAL, tag.c_str(), file.empty() ? nullptr : file.c_str(), 1000, - input.c_str(), logger_function); - - auto return_lengths = [&] { - std::string sizes; - sizes += "expected_output sizes:"; - for (const auto& string : expected_output) { - sizes += " " + std::to_string(string.size()); - } - sizes += "\noutput sizes:"; - for (const auto& string : output) { - sizes += " " + std::to_string(string.size()); - } - return sizes; - }; - - EXPECT_EQ(expected_output, output) << return_lengths(); -} - -TEST(logging_splitters, LogdChunkSplitter_EmptyString) { - TestLogdChunkSplitter("tag", "", "", std::vector{""}); -} - -TEST(logging_splitters, LogdChunkSplitter_BasicString) { - TestLogdChunkSplitter("tag", "", "normal string", std::vector{"normal string"}); -} - -TEST(logging_splitters, LogdChunkSplitter_NormalBasicStringTrailingNewline) { - TestLogdChunkSplitter("tag", "", "normal string\n", std::vector{"normal string\n"}); -} - -TEST(logging_splitters, LogdChunkSplitter_MultilineTrailing) { - TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring", - std::vector{"normal string\nsecond string\nthirdstring"}); -} - -TEST(logging_splitters, LogdChunkSplitter_MultilineTrailingNewline) { - TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring\n", - std::vector{"normal string\nsecond string\nthirdstring\n"}); -} - -TEST(logging_splitters, LogdChunkSplitter_MultilineEmbeddedNewlines) { - TestLogdChunkSplitter( - "tag", "", "normal string\n\n\nsecond string\n\nthirdstring\n", - std::vector{"normal string\n\n\nsecond string\n\nthirdstring\n"}); -} - -// This test should return the same string, the logd logger itself will truncate down to size. -// This has historically been the behavior both in libbase and liblog. -TEST(logging_splitters, LogdChunkSplitter_HugeLineNoNewline) { - auto long_string = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'x'); - ASSERT_EQ(LOGGER_ENTRY_MAX_PAYLOAD, static_cast(long_string.size())); - - TestLogdChunkSplitter("tag", "", long_string, std::vector{long_string}); -} - -std::string ReduceToMaxSize(const std::string& tag, const std::string& string) { - return string.substr(0, LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35); -} - -TEST(logging_splitters, LogdChunkSplitter_MultipleHugeLineNoNewline) { - auto long_string_x = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'x'); - auto long_string_y = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'y'); - auto long_string_z = std::string(LOGGER_ENTRY_MAX_PAYLOAD, 'z'); - - auto long_strings = long_string_x + '\n' + long_string_y + '\n' + long_string_z; - - std::string tag = "tag"; - std::vector expected = {ReduceToMaxSize(tag, long_string_x), ReduceToMaxSize(tag, long_string_y), - long_string_z}; - - TestLogdChunkSplitter(tag, "", long_strings, expected); -} - -// With a ~4k buffer, we should print 2 long strings per logger call. -TEST(logging_splitters, LogdChunkSplitter_Multiple2kLines) { - std::vector expected = { - std::string(2000, 'a') + '\n' + std::string(2000, 'b'), - std::string(2000, 'c') + '\n' + std::string(2000, 'd'), - std::string(2000, 'e') + '\n' + std::string(2000, 'f'), - }; - - auto long_strings = Join(expected, '\n'); - - TestLogdChunkSplitter("tag", "", long_strings, expected); -} - -TEST(logging_splitters, LogdChunkSplitter_ExactSizedLines) { - const char* tag = "tag"; - ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - strlen(tag) - 35; - auto long_string_a = std::string(max_size, 'a'); - auto long_string_b = std::string(max_size, 'b'); - auto long_string_c = std::string(max_size, 'c'); - - auto long_strings = long_string_a + '\n' + long_string_b + '\n' + long_string_c; - - TestLogdChunkSplitter(tag, "", long_strings, - std::vector{long_string_a, long_string_b, long_string_c}); -} - -TEST(logging_splitters, LogdChunkSplitter_UnderEqualOver) { - std::string tag = "tag"; - ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35; - - auto first_string_size = 1000; - auto first_string = std::string(first_string_size, 'a'); - auto second_string_size = max_size - first_string_size - 1; - auto second_string = std::string(second_string_size, 'b'); - - auto exact_string = std::string(max_size, 'c'); - - auto large_string = std::string(max_size + 50, 'd'); - - auto final_string = std::string("final string!\n\nfinal \n \n final \n"); - - std::vector expected = {first_string + '\n' + second_string, exact_string, - ReduceToMaxSize(tag, large_string), final_string}; - - std::vector input_strings = {first_string + '\n' + second_string, exact_string, large_string, - final_string}; - auto long_strings = Join(input_strings, '\n'); - - TestLogdChunkSplitter(tag, "", long_strings, expected); -} - -TEST(logging_splitters, LogdChunkSplitter_WithFile) { - std::string tag = "tag"; - std::string file = "/path/to/myfile.cpp"; - int line = 1000; - auto file_header = StringPrintf("%s:%d] ", file.c_str(), line); - ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - tag.size() - 35; - - auto first_string_size = 1000; - auto first_string = std::string(first_string_size, 'a'); - auto second_string_size = max_size - first_string_size - 1 - 2 * file_header.size(); - auto second_string = std::string(second_string_size, 'b'); - - auto exact_string = std::string(max_size - file_header.size(), 'c'); - - auto large_string = std::string(max_size + 50, 'd'); - - auto final_string = std::string("final string!"); - - std::vector expected = { - file_header + first_string + '\n' + file_header + second_string, file_header + exact_string, - file_header + ReduceToMaxSize(file_header + tag, large_string), file_header + final_string}; - - std::vector input_strings = {first_string + '\n' + second_string, exact_string, large_string, - final_string}; - auto long_strings = Join(input_strings, '\n'); - - TestLogdChunkSplitter(tag, file, long_strings, expected); -} - -// We set max_size based off of tag, so if it's too large, the buffer will be sized wrong. -// We could recover from this, but it's certainly an error for someone to attempt to use a tag this -// large, so we abort instead. -TEST(logging_splitters, LogdChunkSplitter_TooLongTag) { - auto long_tag = std::string(5000, 'x'); - auto logger_function = [](LogId, LogSeverity, const char*, const char*) {}; - ASSERT_DEATH( - SplitByLogdChunks(MAIN, ERROR, long_tag.c_str(), nullptr, 0, "message", logger_function), ""); -} - -// We do handle excessively large file names correctly however. -TEST(logging_splitters, LogdChunkSplitter_TooLongFile) { - auto long_file = std::string(5000, 'x'); - std::string tag = "tag"; - - std::vector expected = {ReduceToMaxSize(tag, long_file), ReduceToMaxSize(tag, long_file)}; - - TestLogdChunkSplitter(tag, long_file, "can't see me\nor me", expected); -} - -void TestStderrOutputGenerator(const char* tag, const char* file, int line, const char* message, - const std::string& expected) { - // All log messages will show "01-01 00:00:00" - struct tm now = { - .tm_sec = 0, - .tm_min = 0, - .tm_hour = 0, - .tm_mday = 1, - .tm_mon = 0, - .tm_year = 1970, - }; - - int pid = 1234; // All log messages will have 1234 for their PID. - uint64_t tid = 4321; // All log messages will have 4321 for their TID. - - auto result = StderrOutputGenerator(now, pid, tid, ERROR, tag, file, line, message); - EXPECT_EQ(expected, result); -} - -TEST(logging_splitters, StderrOutputGenerator_Basic) { - TestStderrOutputGenerator(nullptr, nullptr, 0, "simple message", - "nullptr E 01-01 00:00:00 1234 4321 simple message\n"); - TestStderrOutputGenerator("tag", nullptr, 0, "simple message", - "tag E 01-01 00:00:00 1234 4321 simple message\n"); - TestStderrOutputGenerator( - "tag", "/path/to/some/file", 0, "simple message", - "tag E 01-01 00:00:00 1234 4321 /path/to/some/file:0] simple message\n"); -} - -TEST(logging_splitters, StderrOutputGenerator_NewlineTagAndFile) { - TestStderrOutputGenerator("tag\n\n", nullptr, 0, "simple message", - "tag\n\n E 01-01 00:00:00 1234 4321 simple message\n"); - TestStderrOutputGenerator( - "tag", "/path/to/some/file\n\n", 0, "simple message", - "tag E 01-01 00:00:00 1234 4321 /path/to/some/file\n\n:0] simple message\n"); -} - -TEST(logging_splitters, StderrOutputGenerator_TrailingNewLine) { - TestStderrOutputGenerator( - "tag", nullptr, 0, "simple message\n", - "tag E 01-01 00:00:00 1234 4321 simple message\ntag E 01-01 00:00:00 1234 4321 \n"); -} - -TEST(logging_splitters, StderrOutputGenerator_MultiLine) { - const char* expected_result = - "tag E 01-01 00:00:00 1234 4321 simple message\n" - "tag E 01-01 00:00:00 1234 4321 \n" - "tag E 01-01 00:00:00 1234 4321 \n" - "tag E 01-01 00:00:00 1234 4321 another message \n" - "tag E 01-01 00:00:00 1234 4321 \n" - "tag E 01-01 00:00:00 1234 4321 final message \n" - "tag E 01-01 00:00:00 1234 4321 \n" - "tag E 01-01 00:00:00 1234 4321 \n" - "tag E 01-01 00:00:00 1234 4321 \n"; - - TestStderrOutputGenerator("tag", nullptr, 0, - "simple message\n\n\nanother message \n\n final message \n\n\n", - expected_result); -} - -TEST(logging_splitters, StderrOutputGenerator_MultiLineLong) { - auto long_string_a = std::string(4000, 'a'); - auto long_string_b = std::string(4000, 'b'); - - auto message = long_string_a + '\n' + long_string_b; - auto expected_result = "tag E 01-01 00:00:00 1234 4321 " + long_string_a + '\n' + - "tag E 01-01 00:00:00 1234 4321 " + long_string_b + '\n'; - TestStderrOutputGenerator("tag", nullptr, 0, message.c_str(), expected_result); -} - -} // namespace base -} // namespace android diff --git a/base/logging_test.cpp b/base/logging_test.cpp deleted file mode 100644 index 593e2c100..000000000 --- a/base/logging_test.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/logging.h" - -#include - -#if defined(_WIN32) -#include -#endif - -#include -#include -#include - -#include "android-base/file.h" -#include "android-base/scopeguard.h" -#include "android-base/stringprintf.h" -#include "android-base/test_utils.h" - -#include - -#ifdef __ANDROID__ -#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name) -#else -#define HOST_TEST(suite, name) TEST(suite, name) -#endif - -#if defined(_WIN32) -static void ExitSignalAbortHandler(int) { - _exit(3); -} -#endif - -static void SuppressAbortUI() { -#if defined(_WIN32) - // We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to - // suppress the Windows Error Reporting dialog box, but that API is not - // available in the OS-supplied C Runtime, msvcrt.dll, that we currently - // use (it is available in the Visual Studio C runtime). - // - // Instead, we setup a SIGABRT handler, which is called in abort() right - // before calling Windows Error Reporting. In the handler, we exit the - // process just like abort() does. - ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler)); -#endif -} - -TEST(logging, CHECK) { - ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false "); - CHECK(true); - - ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 "); - CHECK_EQ(0, 0); - - ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");}, - R"(Check failed: "foo" == "bar")"); - CHECK_STREQ("foo", "foo"); - - // Test whether CHECK() and CHECK_STREQ() have a dangling if with no else. - bool flag = false; - if (true) - CHECK(true); - else - flag = true; - EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else"; - - flag = false; - if (true) - CHECK_STREQ("foo", "foo"); - else - flag = true; - EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else"; -} - -TEST(logging, DCHECK) { - if (android::base::kEnableDChecks) { - ASSERT_DEATH({SuppressAbortUI(); DCHECK(false);}, "DCheck failed: false "); - } - DCHECK(true); - - if (android::base::kEnableDChecks) { - ASSERT_DEATH({SuppressAbortUI(); DCHECK_EQ(0, 1);}, "DCheck failed: 0 == 1 "); - } - DCHECK_EQ(0, 0); - - if (android::base::kEnableDChecks) { - ASSERT_DEATH({SuppressAbortUI(); DCHECK_STREQ("foo", "bar");}, - R"(DCheck failed: "foo" == "bar")"); - } - DCHECK_STREQ("foo", "foo"); - - // No testing whether we have a dangling else, possibly. That's inherent to the if (constexpr) - // setup we intentionally chose to force type-checks of debug code even in release builds (so - // we don't get more bit-rot). -} - - -#define CHECK_WOULD_LOG_DISABLED(severity) \ - static_assert(android::base::severity < android::base::FATAL, "Bad input"); \ - for (size_t i = static_cast(android::base::severity) + 1; \ - i <= static_cast(android::base::FATAL); \ - ++i) { \ - { \ - android::base::ScopedLogSeverity sls2(static_cast(i)); \ - EXPECT_FALSE(WOULD_LOG(severity)) << i; \ - } \ - { \ - android::base::ScopedLogSeverity sls2(static_cast(i)); \ - EXPECT_FALSE(WOULD_LOG(::android::base::severity)) << i; \ - } \ - } \ - -#define CHECK_WOULD_LOG_ENABLED(severity) \ - for (size_t i = static_cast(android::base::VERBOSE); \ - i <= static_cast(android::base::severity); \ - ++i) { \ - { \ - android::base::ScopedLogSeverity sls2(static_cast(i)); \ - EXPECT_TRUE(WOULD_LOG(severity)) << i; \ - } \ - { \ - android::base::ScopedLogSeverity sls2(static_cast(i)); \ - EXPECT_TRUE(WOULD_LOG(::android::base::severity)) << i; \ - } \ - } \ - -TEST(logging, WOULD_LOG_FATAL) { - CHECK_WOULD_LOG_ENABLED(FATAL); -} - -TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) { - CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT); -} - -TEST(logging, WOULD_LOG_ERROR_disabled) { - CHECK_WOULD_LOG_DISABLED(ERROR); -} - -TEST(logging, WOULD_LOG_ERROR_enabled) { - CHECK_WOULD_LOG_ENABLED(ERROR); -} - -TEST(logging, WOULD_LOG_WARNING_disabled) { - CHECK_WOULD_LOG_DISABLED(WARNING); -} - -TEST(logging, WOULD_LOG_WARNING_enabled) { - CHECK_WOULD_LOG_ENABLED(WARNING); -} - -TEST(logging, WOULD_LOG_INFO_disabled) { - CHECK_WOULD_LOG_DISABLED(INFO); -} - -TEST(logging, WOULD_LOG_INFO_enabled) { - CHECK_WOULD_LOG_ENABLED(INFO); -} - -TEST(logging, WOULD_LOG_DEBUG_disabled) { - CHECK_WOULD_LOG_DISABLED(DEBUG); -} - -TEST(logging, WOULD_LOG_DEBUG_enabled) { - CHECK_WOULD_LOG_ENABLED(DEBUG); -} - -TEST(logging, WOULD_LOG_VERBOSE_disabled) { - CHECK_WOULD_LOG_DISABLED(VERBOSE); -} - -TEST(logging, WOULD_LOG_VERBOSE_enabled) { - CHECK_WOULD_LOG_ENABLED(VERBOSE); -} - -#undef CHECK_WOULD_LOG_DISABLED -#undef CHECK_WOULD_LOG_ENABLED - - -#if !defined(_WIN32) -static std::string make_log_pattern(android::base::LogSeverity severity, - const char* message) { - static const char log_characters[] = "VDIWEFF"; - static_assert(arraysize(log_characters) - 1 == android::base::FATAL + 1, - "Mismatch in size of log_characters and values in LogSeverity"); - char log_char = log_characters[severity]; - std::string holder(__FILE__); - return android::base::StringPrintf( - "%c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s:\\d+] %s", - log_char, basename(&holder[0]), message); -} -#endif - -static void CheckMessage(const std::string& output, android::base::LogSeverity severity, - const char* expected, const char* expected_tag = nullptr) { - // We can't usefully check the output of any of these on Windows because we - // don't have std::regex, but we can at least make sure we printed at least as - // many characters are in the log message. - ASSERT_GT(output.length(), strlen(expected)); - ASSERT_NE(nullptr, strstr(output.c_str(), expected)) << output; - if (expected_tag != nullptr) { - ASSERT_NE(nullptr, strstr(output.c_str(), expected_tag)) << output; - } - -#if !defined(_WIN32) - std::string regex_str; - if (expected_tag != nullptr) { - regex_str.append(expected_tag); - regex_str.append(" "); - } - regex_str.append(make_log_pattern(severity, expected)); - std::regex message_regex(regex_str); - ASSERT_TRUE(std::regex_search(output, message_regex)) << output; -#endif -} - -static void CheckMessage(CapturedStderr& cap, android::base::LogSeverity severity, - const char* expected, const char* expected_tag = nullptr) { - cap.Stop(); - std::string output = cap.str(); - return CheckMessage(output, severity, expected, expected_tag); -} - -#define CHECK_LOG_STREAM_DISABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - LOG_STREAM(severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - LOG_STREAM(::android::base::severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } - -#define CHECK_LOG_STREAM_ENABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - LOG_STREAM(severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar"); \ - } \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - LOG_STREAM(::android::base::severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar"); \ - } \ - -TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT)); -} - -TEST(logging, LOG_STREAM_ERROR_disabled) { - CHECK_LOG_STREAM_DISABLED(ERROR); -} - -TEST(logging, LOG_STREAM_ERROR_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(ERROR)); -} - -TEST(logging, LOG_STREAM_WARNING_disabled) { - CHECK_LOG_STREAM_DISABLED(WARNING); -} - -TEST(logging, LOG_STREAM_WARNING_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(WARNING)); -} - -TEST(logging, LOG_STREAM_INFO_disabled) { - CHECK_LOG_STREAM_DISABLED(INFO); -} - -TEST(logging, LOG_STREAM_INFO_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(INFO)); -} - -TEST(logging, LOG_STREAM_DEBUG_disabled) { - CHECK_LOG_STREAM_DISABLED(DEBUG); -} - -TEST(logging, LOG_STREAM_DEBUG_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(DEBUG)); -} - -TEST(logging, LOG_STREAM_VERBOSE_disabled) { - CHECK_LOG_STREAM_DISABLED(VERBOSE); -} - -TEST(logging, LOG_STREAM_VERBOSE_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(VERBOSE)); -} - -#undef CHECK_LOG_STREAM_DISABLED -#undef CHECK_LOG_STREAM_ENABLED - -#define CHECK_LOG_DISABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - LOG(severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - LOG(::android::base::severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } - -#define CHECK_LOG_ENABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - LOG(severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar"); \ - } \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - LOG(::android::base::severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar"); \ - } \ - -TEST(logging, LOG_FATAL) { - ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar"); - ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar"); -} - -TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT)); -} - -TEST(logging, LOG_ERROR_disabled) { - CHECK_LOG_DISABLED(ERROR); -} - -TEST(logging, LOG_ERROR_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(ERROR)); -} - -TEST(logging, LOG_WARNING_disabled) { - CHECK_LOG_DISABLED(WARNING); -} - -TEST(logging, LOG_WARNING_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(WARNING)); -} - -TEST(logging, LOG_INFO_disabled) { - CHECK_LOG_DISABLED(INFO); -} - -TEST(logging, LOG_INFO_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(INFO)); -} - -TEST(logging, LOG_DEBUG_disabled) { - CHECK_LOG_DISABLED(DEBUG); -} - -TEST(logging, LOG_DEBUG_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(DEBUG)); -} - -TEST(logging, LOG_VERBOSE_disabled) { - CHECK_LOG_DISABLED(VERBOSE); -} - -TEST(logging, LOG_VERBOSE_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(VERBOSE)); -} - -#undef CHECK_LOG_DISABLED -#undef CHECK_LOG_ENABLED - -TEST(logging, LOG_complex_param) { -#define CHECK_LOG_COMBINATION(use_scoped_log_severity_info, use_logging_severity_info) \ - { \ - android::base::ScopedLogSeverity sls( \ - (use_scoped_log_severity_info) ? ::android::base::INFO : ::android::base::WARNING); \ - CapturedStderr cap; \ - LOG((use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING) \ - << "foobar"; \ - if ((use_scoped_log_severity_info) || !(use_logging_severity_info)) { \ - ASSERT_NO_FATAL_FAILURE(CheckMessage( \ - cap, (use_logging_severity_info) ? ::android::base::INFO : ::android::base::WARNING, \ - "foobar")); \ - } else { \ - cap.Stop(); \ - ASSERT_EQ("", cap.str()); \ - } \ - } - - CHECK_LOG_COMBINATION(false,false); - CHECK_LOG_COMBINATION(false,true); - CHECK_LOG_COMBINATION(true,false); - CHECK_LOG_COMBINATION(true,true); - -#undef CHECK_LOG_COMBINATION -} - - -TEST(logging, LOG_does_not_clobber_errno) { - CapturedStderr cap; - errno = 12345; - LOG(INFO) << (errno = 67890); - EXPECT_EQ(12345, errno) << "errno was not restored"; - - ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890")); -} - -TEST(logging, PLOG_does_not_clobber_errno) { - CapturedStderr cap; - errno = 12345; - PLOG(INFO) << (errno = 67890); - EXPECT_EQ(12345, errno) << "errno was not restored"; - - ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::INFO, "67890")); -} - -TEST(logging, LOG_does_not_have_dangling_if) { - CapturedStderr cap; // So the logging below has no side-effects. - - // Do the test two ways: once where we hypothesize that LOG()'s if - // will evaluate to true (when severity is high enough) and once when we - // expect it to evaluate to false (when severity is not high enough). - bool flag = false; - if (true) - LOG(INFO) << "foobar"; - else - flag = true; - - EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else"; - - flag = false; - if (true) - LOG(VERBOSE) << "foobar"; - else - flag = true; - - EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else"; -} - -#define CHECK_PLOG_DISABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - PLOG(severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } \ - { \ - android::base::ScopedLogSeverity sls1(android::base::FATAL); \ - CapturedStderr cap1; \ - PLOG(severity) << "foo bar"; \ - cap1.Stop(); \ - ASSERT_EQ("", cap1.str()); \ - } - -#define CHECK_PLOG_ENABLED(severity) \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - errno = ENOENT; \ - PLOG(severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \ - } \ - { \ - android::base::ScopedLogSeverity sls2(android::base::severity); \ - CapturedStderr cap2; \ - errno = ENOENT; \ - PLOG(severity) << "foobar"; \ - CheckMessage(cap2, android::base::severity, "foobar: No such file or directory"); \ - } \ - -TEST(logging, PLOG_FATAL) { - ASSERT_DEATH({SuppressAbortUI(); PLOG(FATAL) << "foobar";}, "foobar"); - ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar"); -} - -TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT)); -} - -TEST(logging, PLOG_ERROR_disabled) { - CHECK_PLOG_DISABLED(ERROR); -} - -TEST(logging, PLOG_ERROR_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(ERROR)); -} - -TEST(logging, PLOG_WARNING_disabled) { - CHECK_PLOG_DISABLED(WARNING); -} - -TEST(logging, PLOG_WARNING_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(WARNING)); -} - -TEST(logging, PLOG_INFO_disabled) { - CHECK_PLOG_DISABLED(INFO); -} - -TEST(logging, PLOG_INFO_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(INFO)); -} - -TEST(logging, PLOG_DEBUG_disabled) { - CHECK_PLOG_DISABLED(DEBUG); -} - -TEST(logging, PLOG_DEBUG_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(DEBUG)); -} - -TEST(logging, PLOG_VERBOSE_disabled) { - CHECK_PLOG_DISABLED(VERBOSE); -} - -TEST(logging, PLOG_VERBOSE_enabled) { - ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(VERBOSE)); -} - -#undef CHECK_PLOG_DISABLED -#undef CHECK_PLOG_ENABLED - - -TEST(logging, UNIMPLEMENTED) { - std::string expected = android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__); - - CapturedStderr cap; - errno = ENOENT; - UNIMPLEMENTED(ERROR); - ASSERT_NO_FATAL_FAILURE(CheckMessage(cap, android::base::ERROR, expected.c_str())); -} - -static void NoopAborter(const char* msg ATTRIBUTE_UNUSED) { - LOG(ERROR) << "called noop"; -} - -TEST(logging, LOG_FATAL_NOOP_ABORTER) { - CapturedStderr cap; - { - android::base::SetAborter(NoopAborter); - - android::base::ScopedLogSeverity sls(android::base::ERROR); - LOG(FATAL) << "foobar"; - cap.Stop(); - - android::base::SetAborter(android::base::DefaultAborter); - } - std::string output = cap.str(); - ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::FATAL, "foobar")); - ASSERT_NO_FATAL_FAILURE(CheckMessage(output, android::base::ERROR, "called noop")); - - ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar"); -} - -struct CountLineAborter { - static void CountLineAborterFunction(const char* msg) { - while (*msg != 0) { - if (*msg == '\n') { - newline_count++; - } - msg++; - } - } - static size_t newline_count; -}; -size_t CountLineAborter::newline_count = 0; - -TEST(logging, LOG_FATAL_ABORTER_MESSAGE) { - CountLineAborter::newline_count = 0; - android::base::SetAborter(CountLineAborter::CountLineAborterFunction); - - android::base::ScopedLogSeverity sls(android::base::ERROR); - CapturedStderr cap; - LOG(FATAL) << "foo\nbar"; - - EXPECT_EQ(CountLineAborter::newline_count, 1U); -} - -__attribute__((constructor)) void TestLoggingInConstructor() { - LOG(ERROR) << "foobar"; -} - -TEST(logging, StdioLogger) { - CapturedStderr cap_err; - CapturedStdout cap_out; - android::base::SetLogger(android::base::StdioLogger); - LOG(INFO) << "out"; - LOG(ERROR) << "err"; - cap_err.Stop(); - cap_out.Stop(); - - // For INFO we expect just the literal "out\n". - ASSERT_EQ("out\n", cap_out.str()); - // Whereas ERROR logging includes the program name. - ASSERT_EQ(android::base::Basename(android::base::GetExecutablePath()) + ": err\n", cap_err.str()); -} - -TEST(logging, ForkSafe) { -#if !defined(_WIN32) - using namespace android::base; - SetLogger( - [&](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) { sleep(3); }); - - auto guard = make_scope_guard([&] { -#ifdef __ANDROID__ - SetLogger(LogdLogger()); -#else - SetLogger(StderrLogger); -#endif - }); - - auto thread = std::thread([] { - LOG(ERROR) << "This should sleep for 3 seconds, long enough to fork another process, if there " - "is no intervention"; - }); - thread.detach(); - - auto pid = fork(); - ASSERT_NE(-1, pid); - - if (pid == 0) { - // Reset the logger, so the next message doesn't sleep(). - SetLogger([](LogId, LogSeverity, const char*, const char*, unsigned int, const char*) {}); - LOG(ERROR) << "This should succeed in the child, only if libbase is forksafe."; - _exit(EXIT_SUCCESS); - } - - // Wait for up to 3 seconds for the child to exit. - int tries = 3; - bool found_child = false; - while (tries-- > 0) { - auto result = waitpid(pid, nullptr, WNOHANG); - EXPECT_NE(-1, result); - if (result == pid) { - found_child = true; - break; - } - sleep(1); - } - - EXPECT_TRUE(found_child); - - // Kill the child if it did not exit. - if (!found_child) { - kill(pid, SIGKILL); - } -#endif -} diff --git a/base/macros_test.cpp b/base/macros_test.cpp deleted file mode 100644 index 2b522db5c..000000000 --- a/base/macros_test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2018 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 "android-base/macros.h" - -#include - -#include - -TEST(macros, SIZEOF_MEMBER_macro) { - struct S { - int32_t i32; - double d; - }; - ASSERT_EQ(4U, SIZEOF_MEMBER(S, i32)); - ASSERT_EQ(8U, SIZEOF_MEMBER(S, d)); -} diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp deleted file mode 100644 index fff345384..000000000 --- a/base/mapped_file.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2018 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 "android-base/mapped_file.h" - -#include - -#include - -namespace android { -namespace base { - -static constexpr char kEmptyBuffer[] = {'0'}; - -static off64_t InitPageSize() { -#if defined(_WIN32) - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwAllocationGranularity; -#else - return sysconf(_SC_PAGE_SIZE); -#endif -} - -std::unique_ptr MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length, - int prot) { -#if defined(_WIN32) - return FromOsHandle(reinterpret_cast(_get_osfhandle(fd.get())), offset, length, prot); -#else - return FromOsHandle(fd.get(), offset, length, prot); -#endif -} - -std::unique_ptr MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length, - int prot) { - static const off64_t page_size = InitPageSize(); - size_t slop = offset % page_size; - off64_t file_offset = offset - slop; - off64_t file_length = length + slop; - -#if defined(_WIN32) - HANDLE handle = CreateFileMappingW( - h, nullptr, (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr); - if (handle == nullptr) { - // http://b/119818070 "app crashes when reading asset of zero length". - // Return a MappedFile that's only valid for reading the size. - if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) { - return std::unique_ptr( - new MappedFile(const_cast(kEmptyBuffer), 0, 0, nullptr)); - } - return nullptr; - } - void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0, - file_offset, file_length); - if (base == nullptr) { - CloseHandle(handle); - return nullptr; - } - return std::unique_ptr( - new MappedFile(static_cast(base), length, slop, handle)); -#else - void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset); - if (base == MAP_FAILED) { - // http://b/119818070 "app crashes when reading asset of zero length". - // mmap fails with EINVAL for a zero length region. - if (errno == EINVAL && length == 0) { - return std::unique_ptr(new MappedFile(const_cast(kEmptyBuffer), 0, 0)); - } - return nullptr; - } - return std::unique_ptr(new MappedFile(static_cast(base), length, slop)); -#endif -} - -MappedFile::MappedFile(MappedFile&& other) - : base_(std::exchange(other.base_, nullptr)), - size_(std::exchange(other.size_, 0)), - offset_(std::exchange(other.offset_, 0)) -#ifdef _WIN32 - , - handle_(std::exchange(other.handle_, nullptr)) -#endif -{ -} - -MappedFile& MappedFile::operator=(MappedFile&& other) { - Close(); - base_ = std::exchange(other.base_, nullptr); - size_ = std::exchange(other.size_, 0); - offset_ = std::exchange(other.offset_, 0); -#ifdef _WIN32 - handle_ = std::exchange(other.handle_, nullptr); -#endif - return *this; -} - -MappedFile::~MappedFile() { - Close(); -} - -void MappedFile::Close() { -#if defined(_WIN32) - if (base_ != nullptr && size_ != 0) UnmapViewOfFile(base_); - if (handle_ != nullptr) CloseHandle(handle_); - handle_ = nullptr; -#else - if (base_ != nullptr && size_ != 0) munmap(base_, size_ + offset_); -#endif - - base_ = nullptr; - offset_ = size_ = 0; -} - -} // namespace base -} // namespace android diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp deleted file mode 100644 index d21703c78..000000000 --- a/base/mapped_file_test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2018 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 "android-base/mapped_file.h" - -#include - -#include -#include -#include - -#include - -#include "android-base/file.h" - -TEST(mapped_file, smoke) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - ASSERT_TRUE(android::base::WriteStringToFd("hello world", tf.fd)); - - auto m = android::base::MappedFile::FromFd(tf.fd, 3, 2, PROT_READ); - ASSERT_EQ(2u, m->size()); - ASSERT_EQ('l', m->data()[0]); - ASSERT_EQ('o', m->data()[1]); -} - -TEST(mapped_file, zero_length_mapping) { - // http://b/119818070 "app crashes when reading asset of zero length". - // mmap fails with EINVAL for a zero length region. - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ); - EXPECT_EQ(0u, m->size()); - EXPECT_NE(nullptr, m->data()); -} diff --git a/base/no_destructor_test.cpp b/base/no_destructor_test.cpp deleted file mode 100644 index f19468abf..000000000 --- a/base/no_destructor_test.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/no_destructor.h" - -#include - -struct __attribute__((packed)) Bomb { - Bomb() : magic_(123) {} - - ~Bomb() { exit(42); } - - int get() const { return magic_; } - - private: - [[maybe_unused]] char padding_; - int magic_; -}; - -TEST(no_destructor, bomb) { - ASSERT_EXIT(({ - { - Bomb b; - if (b.get() != 123) exit(1); - } - - exit(0); - }), - ::testing::ExitedWithCode(42), ""); -} - -TEST(no_destructor, defused) { - ASSERT_EXIT(({ - { - android::base::NoDestructor b; - if (b->get() != 123) exit(1); - } - - exit(0); - }), - ::testing::ExitedWithCode(0), ""); -} - -TEST(no_destructor, operators) { - android::base::NoDestructor b; - const android::base::NoDestructor& c = b; - ASSERT_EQ(123, b.get()->get()); - ASSERT_EQ(123, b->get()); - ASSERT_EQ(123, (*b).get()); - ASSERT_EQ(123, c.get()->get()); - ASSERT_EQ(123, c->get()); - ASSERT_EQ(123, (*c).get()); -} diff --git a/base/parsebool.cpp b/base/parsebool.cpp deleted file mode 100644 index ff96fe9a9..000000000 --- a/base/parsebool.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/parsebool.h" -#include - -namespace android { -namespace base { - -ParseBoolResult ParseBool(std::string_view s) { - if (s == "1" || s == "y" || s == "yes" || s == "on" || s == "true") { - return ParseBoolResult::kTrue; - } - if (s == "0" || s == "n" || s == "no" || s == "off" || s == "false") { - return ParseBoolResult::kFalse; - } - return ParseBoolResult::kError; -} - -} // namespace base -} // namespace android diff --git a/base/parsebool_test.cpp b/base/parsebool_test.cpp deleted file mode 100644 index a0819940b..000000000 --- a/base/parsebool_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/parsebool.h" - -#include - -#include -#include - -using android::base::ParseBool; -using android::base::ParseBoolResult; - -TEST(parsebool, true_) { - static const char* yes[] = { - "1", "on", "true", "y", "yes", - }; - for (const char* s : yes) { - ASSERT_EQ(ParseBoolResult::kTrue, ParseBool(s)); - } -} - -TEST(parsebool, false_) { - static const char* no[] = { - "0", "false", "n", "no", "off", - }; - for (const char* s : no) { - ASSERT_EQ(ParseBoolResult::kFalse, ParseBool(s)); - } -} - -TEST(parsebool, invalid) { - ASSERT_EQ(ParseBoolResult::kError, ParseBool("blarg")); - ASSERT_EQ(ParseBoolResult::kError, ParseBool("")); -} diff --git a/base/parsedouble_test.cpp b/base/parsedouble_test.cpp deleted file mode 100644 index ec3c10c74..000000000 --- a/base/parsedouble_test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/parsedouble.h" - -#include - -TEST(parsedouble, double_smoke) { - double d; - ASSERT_FALSE(android::base::ParseDouble("", &d)); - ASSERT_FALSE(android::base::ParseDouble("x", &d)); - ASSERT_FALSE(android::base::ParseDouble("123.4x", &d)); - - ASSERT_TRUE(android::base::ParseDouble("123.4", &d)); - ASSERT_DOUBLE_EQ(123.4, d); - ASSERT_TRUE(android::base::ParseDouble("-123.4", &d)); - ASSERT_DOUBLE_EQ(-123.4, d); - - ASSERT_TRUE(android::base::ParseDouble("0", &d, 0.0)); - ASSERT_DOUBLE_EQ(0.0, d); - ASSERT_FALSE(android::base::ParseDouble("0", &d, 1e-9)); - ASSERT_FALSE(android::base::ParseDouble("3.0", &d, -1.0, 2.0)); - ASSERT_TRUE(android::base::ParseDouble("1.0", &d, 0.0, 2.0)); - ASSERT_DOUBLE_EQ(1.0, d); - - ASSERT_FALSE(android::base::ParseDouble("123.4x", nullptr)); - ASSERT_TRUE(android::base::ParseDouble("-123.4", nullptr)); - ASSERT_FALSE(android::base::ParseDouble("3.0", nullptr, -1.0, 2.0)); - ASSERT_TRUE(android::base::ParseDouble("1.0", nullptr, 0.0, 2.0)); -} - -TEST(parsedouble, float_smoke) { - float f; - ASSERT_FALSE(android::base::ParseFloat("", &f)); - ASSERT_FALSE(android::base::ParseFloat("x", &f)); - ASSERT_FALSE(android::base::ParseFloat("123.4x", &f)); - - ASSERT_TRUE(android::base::ParseFloat("123.4", &f)); - ASSERT_FLOAT_EQ(123.4, f); - ASSERT_TRUE(android::base::ParseFloat("-123.4", &f)); - ASSERT_FLOAT_EQ(-123.4, f); - - ASSERT_TRUE(android::base::ParseFloat("0", &f, 0.0)); - ASSERT_FLOAT_EQ(0.0, f); - ASSERT_FALSE(android::base::ParseFloat("0", &f, 1e-9)); - ASSERT_FALSE(android::base::ParseFloat("3.0", &f, -1.0, 2.0)); - ASSERT_TRUE(android::base::ParseFloat("1.0", &f, 0.0, 2.0)); - ASSERT_FLOAT_EQ(1.0, f); - - ASSERT_FALSE(android::base::ParseFloat("123.4x", nullptr)); - ASSERT_TRUE(android::base::ParseFloat("-123.4", nullptr)); - ASSERT_FALSE(android::base::ParseFloat("3.0", nullptr, -1.0, 2.0)); - ASSERT_TRUE(android::base::ParseFloat("1.0", nullptr, 0.0, 2.0)); -} diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp deleted file mode 100644 index e449c3345..000000000 --- a/base/parseint_test.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/parseint.h" - -#include - -#include - -TEST(parseint, signed_smoke) { - errno = 0; - int i = 0; - ASSERT_FALSE(android::base::ParseInt("x", &i)); - ASSERT_EQ(EINVAL, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseInt("123x", &i)); - ASSERT_EQ(EINVAL, errno); - - ASSERT_TRUE(android::base::ParseInt("123", &i)); - ASSERT_EQ(123, i); - ASSERT_EQ(0, errno); - i = 0; - EXPECT_TRUE(android::base::ParseInt(" 123", &i)); - EXPECT_EQ(123, i); - ASSERT_TRUE(android::base::ParseInt("-123", &i)); - ASSERT_EQ(-123, i); - i = 0; - EXPECT_TRUE(android::base::ParseInt(" -123", &i)); - EXPECT_EQ(-123, i); - - short s = 0; - ASSERT_TRUE(android::base::ParseInt("1234", &s)); - ASSERT_EQ(1234, s); - - ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15)); - ASSERT_EQ(12, i); - errno = 0; - ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15)); - ASSERT_EQ(ERANGE, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15)); - ASSERT_EQ(ERANGE, errno); - - errno = 0; - ASSERT_FALSE(android::base::ParseInt("x", nullptr)); - ASSERT_EQ(EINVAL, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseInt("123x", nullptr)); - ASSERT_EQ(EINVAL, errno); - ASSERT_TRUE(android::base::ParseInt("1234", nullptr)); -} - -TEST(parseint, unsigned_smoke) { - errno = 0; - unsigned int i = 0u; - ASSERT_FALSE(android::base::ParseUint("x", &i)); - ASSERT_EQ(EINVAL, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseUint("123x", &i)); - ASSERT_EQ(EINVAL, errno); - - ASSERT_TRUE(android::base::ParseUint("123", &i)); - ASSERT_EQ(123u, i); - ASSERT_EQ(0, errno); - i = 0u; - EXPECT_TRUE(android::base::ParseUint(" 123", &i)); - EXPECT_EQ(123u, i); - errno = 0; - ASSERT_FALSE(android::base::ParseUint("-123", &i)); - EXPECT_EQ(EINVAL, errno); - errno = 0; - EXPECT_FALSE(android::base::ParseUint(" -123", &i)); - EXPECT_EQ(EINVAL, errno); - - unsigned short s = 0u; - ASSERT_TRUE(android::base::ParseUint("1234", &s)); - ASSERT_EQ(1234u, s); - - ASSERT_TRUE(android::base::ParseUint("12", &i, 15u)); - ASSERT_EQ(12u, i); - errno = 0; - ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u)); - ASSERT_EQ(EINVAL, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseUint("16", &i, 15u)); - ASSERT_EQ(ERANGE, errno); - - errno = 0; - ASSERT_FALSE(android::base::ParseUint("x", nullptr)); - ASSERT_EQ(EINVAL, errno); - errno = 0; - ASSERT_FALSE(android::base::ParseUint("123x", nullptr)); - ASSERT_EQ(EINVAL, errno); - ASSERT_TRUE(android::base::ParseUint("1234", nullptr)); - - errno = 0; - unsigned long long int lli; - EXPECT_FALSE(android::base::ParseUint("-123", &lli)); - EXPECT_EQ(EINVAL, errno); - errno = 0; - EXPECT_FALSE(android::base::ParseUint(" -123", &lli)); - EXPECT_EQ(EINVAL, errno); -} - -TEST(parseint, no_implicit_octal) { - int i = 0; - ASSERT_TRUE(android::base::ParseInt("0123", &i)); - ASSERT_EQ(123, i); - - unsigned int u = 0u; - ASSERT_TRUE(android::base::ParseUint("0123", &u)); - ASSERT_EQ(123u, u); -} - -TEST(parseint, explicit_hex) { - int i = 0; - ASSERT_TRUE(android::base::ParseInt("0x123", &i)); - ASSERT_EQ(0x123, i); - i = 0; - EXPECT_TRUE(android::base::ParseInt(" 0x123", &i)); - EXPECT_EQ(0x123, i); - - unsigned int u = 0u; - ASSERT_TRUE(android::base::ParseUint("0x123", &u)); - ASSERT_EQ(0x123u, u); - u = 0u; - EXPECT_TRUE(android::base::ParseUint(" 0x123", &u)); - EXPECT_EQ(0x123u, u); -} - -TEST(parseint, string) { - int i = 0; - ASSERT_TRUE(android::base::ParseInt(std::string("123"), &i)); - ASSERT_EQ(123, i); - - unsigned int u = 0u; - ASSERT_TRUE(android::base::ParseUint(std::string("123"), &u)); - ASSERT_EQ(123u, u); -} - -TEST(parseint, untouched_on_failure) { - int i = 123; - ASSERT_FALSE(android::base::ParseInt("456x", &i)); - ASSERT_EQ(123, i); - - unsigned int u = 123u; - ASSERT_FALSE(android::base::ParseUint("456x", &u)); - ASSERT_EQ(123u, u); -} - -TEST(parseint, ParseByteCount) { - uint64_t i = 0; - ASSERT_TRUE(android::base::ParseByteCount("123b", &i)); - ASSERT_EQ(123ULL, i); - - ASSERT_TRUE(android::base::ParseByteCount("8k", &i)); - ASSERT_EQ(8ULL * 1024, i); - - ASSERT_TRUE(android::base::ParseByteCount("8M", &i)); - ASSERT_EQ(8ULL * 1024 * 1024, i); - - ASSERT_TRUE(android::base::ParseByteCount("6g", &i)); - ASSERT_EQ(6ULL * 1024 * 1024 * 1024, i); - - ASSERT_TRUE(android::base::ParseByteCount("1T", &i)); - ASSERT_EQ(1ULL * 1024 * 1024 * 1024 * 1024, i); - - ASSERT_TRUE(android::base::ParseByteCount("2p", &i)); - ASSERT_EQ(2ULL * 1024 * 1024 * 1024 * 1024 * 1024, i); - - ASSERT_TRUE(android::base::ParseByteCount("4e", &i)); - ASSERT_EQ(4ULL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, i); -} - -TEST(parseint, ParseByteCount_invalid_suffix) { - unsigned u; - ASSERT_FALSE(android::base::ParseByteCount("1x", &u)); -} - -TEST(parseint, ParseByteCount_overflow) { - uint64_t u64; - ASSERT_FALSE(android::base::ParseByteCount("4294967295E", &u64)); - - uint16_t u16; - ASSERT_TRUE(android::base::ParseByteCount("63k", &u16)); - ASSERT_EQ(63U * 1024, u16); - ASSERT_TRUE(android::base::ParseByteCount("65535b", &u16)); - ASSERT_EQ(65535U, u16); - ASSERT_FALSE(android::base::ParseByteCount("65k", &u16)); -} diff --git a/base/parsenetaddress.cpp b/base/parsenetaddress.cpp deleted file mode 100644 index dd80f6da2..000000000 --- a/base/parsenetaddress.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/parsenetaddress.h" - -#include - -#include "android-base/stringprintf.h" -#include "android-base/strings.h" - -namespace android { -namespace base { - -bool ParseNetAddress(const std::string& address, std::string* host, int* port, - std::string* canonical_address, std::string* error) { - host->clear(); - - bool ipv6 = true; - bool saw_port = false; - size_t colons = std::count(address.begin(), address.end(), ':'); - size_t dots = std::count(address.begin(), address.end(), '.'); - std::string port_str; - if (address[0] == '[') { - // [::1]:123 - if (address.rfind("]:") == std::string::npos) { - *error = StringPrintf("bad IPv6 address '%s'", address.c_str()); - return false; - } - *host = address.substr(1, (address.find("]:") - 1)); - port_str = address.substr(address.rfind("]:") + 2); - saw_port = true; - } else if (dots == 0 && colons >= 2 && colons <= 7) { - // ::1 - *host = address; - } else if (colons <= 1) { - // 1.2.3.4 or some.accidental.domain.com - ipv6 = false; - std::vector pieces = Split(address, ":"); - *host = pieces[0]; - if (pieces.size() > 1) { - port_str = pieces[1]; - saw_port = true; - } - } - - if (host->empty()) { - *error = StringPrintf("no host in '%s'", address.c_str()); - return false; - } - - if (saw_port) { - if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 || - *port > 65535) { - *error = StringPrintf("bad port number '%s' in '%s'", port_str.c_str(), - address.c_str()); - return false; - } - } - - if (canonical_address != nullptr) { - *canonical_address = - StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port); - } - - return true; -} - -} // namespace base -} // namespace android diff --git a/base/parsenetaddress_test.cpp b/base/parsenetaddress_test.cpp deleted file mode 100644 index a3bfac860..000000000 --- a/base/parsenetaddress_test.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/parsenetaddress.h" - -#include - -using android::base::ParseNetAddress; - -TEST(ParseNetAddressTest, TestUrl) { - std::string canonical, host, error; - int port = 123; - - EXPECT_TRUE( - ParseNetAddress("www.google.com", &host, &port, &canonical, &error)); - EXPECT_EQ("www.google.com:123", canonical); - EXPECT_EQ("www.google.com", host); - EXPECT_EQ(123, port); - - EXPECT_TRUE( - ParseNetAddress("www.google.com:666", &host, &port, &canonical, &error)); - EXPECT_EQ("www.google.com:666", canonical); - EXPECT_EQ("www.google.com", host); - EXPECT_EQ(666, port); -} - -TEST(ParseNetAddressTest, TestIpv4) { - std::string canonical, host, error; - int port = 123; - - EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, &canonical, &error)); - EXPECT_EQ("1.2.3.4:123", canonical); - EXPECT_EQ("1.2.3.4", host); - EXPECT_EQ(123, port); - - EXPECT_TRUE(ParseNetAddress("1.2.3.4:666", &host, &port, &canonical, &error)); - EXPECT_EQ("1.2.3.4:666", canonical); - EXPECT_EQ("1.2.3.4", host); - EXPECT_EQ(666, port); -} - -TEST(ParseNetAddressTest, TestIpv6) { - std::string canonical, host, error; - int port = 123; - - EXPECT_TRUE(ParseNetAddress("::1", &host, &port, &canonical, &error)); - EXPECT_EQ("[::1]:123", canonical); - EXPECT_EQ("::1", host); - EXPECT_EQ(123, port); - - EXPECT_TRUE(ParseNetAddress("fe80::200:5aee:feaa:20a2", &host, &port, - &canonical, &error)); - EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical); - EXPECT_EQ("fe80::200:5aee:feaa:20a2", host); - EXPECT_EQ(123, port); - - EXPECT_TRUE(ParseNetAddress("[::1]:666", &host, &port, &canonical, &error)); - EXPECT_EQ("[::1]:666", canonical); - EXPECT_EQ("::1", host); - EXPECT_EQ(666, port); - - EXPECT_TRUE(ParseNetAddress("[fe80::200:5aee:feaa:20a2]:666", &host, &port, - &canonical, &error)); - EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical); - EXPECT_EQ("fe80::200:5aee:feaa:20a2", host); - EXPECT_EQ(666, port); -} - -TEST(ParseNetAddressTest, TestInvalidAddress) { - std::string canonical, host; - int port; - - std::string failure_cases[] = { - // Invalid IPv4. - "1.2.3.4:", - "1.2.3.4::", - ":123", - - // Invalid IPv6. - ":1", - "::::::::1", - "[::1", - "[::1]", - "[::1]:", - "[::1]::", - - // Invalid port. - "1.2.3.4:-1", - "1.2.3.4:0", - "1.2.3.4:65536" - "1.2.3.4:hello", - "[::1]:-1", - "[::1]:0", - "[::1]:65536", - "[::1]:hello", - }; - - for (const auto& address : failure_cases) { - // Failure should give some non-empty error string. - std::string error; - EXPECT_FALSE(ParseNetAddress(address, &host, &port, &canonical, &error)); - EXPECT_NE("", error); - } -} - -// Null canonical address argument. -TEST(ParseNetAddressTest, TestNullCanonicalAddress) { - std::string host, error; - int port = 42; - - EXPECT_TRUE(ParseNetAddress("www.google.com", &host, &port, nullptr, &error)); - EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, nullptr, &error)); - EXPECT_TRUE(ParseNetAddress("::1", &host, &port, nullptr, &error)); -} diff --git a/base/process.cpp b/base/process.cpp deleted file mode 100644 index b8cabf657..000000000 --- a/base/process.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/process.h" - -namespace android { -namespace base { - -void AllPids::PidIterator::Increment() { - if (!dir_) { - return; - } - - dirent* de; - while ((de = readdir(dir_.get())) != nullptr) { - pid_t pid = atoi(de->d_name); - if (pid != 0) { - pid_ = pid; - return; - } - } - pid_ = -1; -} - -} // namespace base -} // namespace android diff --git a/base/process_test.cpp b/base/process_test.cpp deleted file mode 100644 index 056f6679f..000000000 --- a/base/process_test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2019 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 "android-base/process.h" - -#include - -#include - -TEST(process, find_ourselves) { -#if defined(__linux__) - bool found_our_pid = false; - for (const auto& pid : android::base::AllPids{}) { - if (pid == getpid()) { - found_our_pid = true; - } - } - - EXPECT_TRUE(found_our_pid); - -#endif -} diff --git a/base/properties.cpp b/base/properties.cpp deleted file mode 100644 index 5c9ec7e9c..000000000 --- a/base/properties.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/properties.h" - -#if defined(__BIONIC__) -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace android { -namespace base { - -bool GetBoolProperty(const std::string& key, bool default_value) { - switch (ParseBool(GetProperty(key, ""))) { - case ParseBoolResult::kError: - return default_value; - case ParseBoolResult::kFalse: - return false; - case ParseBoolResult::kTrue: - return true; - } - __builtin_unreachable(); -} - -template -T GetIntProperty(const std::string& key, T default_value, T min, T max) { - T result; - std::string value = GetProperty(key, ""); - if (!value.empty() && android::base::ParseInt(value, &result, min, max)) return result; - return default_value; -} - -template -T GetUintProperty(const std::string& key, T default_value, T max) { - T result; - std::string value = GetProperty(key, ""); - if (!value.empty() && android::base::ParseUint(value, &result, max)) return result; - return default_value; -} - -template int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t); -template int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t); -template int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t); -template int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t); - -template uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t); -template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t); -template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t); -template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t); - -#if !defined(__BIONIC__) -static std::map& g_properties = *new std::map; -static int __system_property_set(const char* key, const char* value) { - g_properties[key] = value; - return 0; -} -#endif - -std::string GetProperty(const std::string& key, const std::string& default_value) { - std::string property_value; -#if defined(__BIONIC__) - const prop_info* pi = __system_property_find(key.c_str()); - if (pi == nullptr) return default_value; - - __system_property_read_callback(pi, - [](void* cookie, const char*, const char* value, unsigned) { - auto property_value = reinterpret_cast(cookie); - *property_value = value; - }, - &property_value); -#else - auto it = g_properties.find(key); - if (it == g_properties.end()) return default_value; - property_value = it->second; -#endif - // If the property exists but is empty, also return the default value. - // Since we can't remove system properties, "empty" is traditionally - // the same as "missing" (this was true for cutils' property_get). - return property_value.empty() ? default_value : property_value; -} - -bool SetProperty(const std::string& key, const std::string& value) { - return (__system_property_set(key.c_str(), value.c_str()) == 0); -} - -#if defined(__BIONIC__) - -struct WaitForPropertyData { - bool done; - const std::string* expected_value; - unsigned last_read_serial; -}; - -static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) { - WaitForPropertyData* data = reinterpret_cast(data_ptr); - if (*data->expected_value == value) { - data->done = true; - } else { - data->last_read_serial = serial; - } -} - -// TODO: chrono_utils? -static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) { - auto s = std::chrono::duration_cast(d); - auto ns = std::chrono::duration_cast(d - s); - ts.tv_sec = std::min(s.count(), std::numeric_limits::max()); - ts.tv_nsec = ns.count(); -} - -using AbsTime = std::chrono::time_point; - -static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout, - const AbsTime& start_time) { - auto now = std::chrono::steady_clock::now(); - auto time_elapsed = std::chrono::duration_cast(now - start_time); - if (time_elapsed >= relative_timeout) { - ts = { 0, 0 }; - } else { - auto remaining_timeout = relative_timeout - time_elapsed; - DurationToTimeSpec(ts, remaining_timeout); - } -} - -// Waits for the system property `key` to be created. -// Times out after `relative_timeout`. -// Sets absolute_timeout which represents absolute time for the timeout. -// Returns nullptr on timeout. -static const prop_info* WaitForPropertyCreation(const std::string& key, - const std::chrono::milliseconds& relative_timeout, - const AbsTime& start_time) { - // Find the property's prop_info*. - const prop_info* pi; - unsigned global_serial = 0; - while ((pi = __system_property_find(key.c_str())) == nullptr) { - // The property doesn't even exist yet. - // Wait for a global change and then look again. - timespec ts; - UpdateTimeSpec(ts, relative_timeout, start_time); - if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr; - } - return pi; -} - -bool WaitForProperty(const std::string& key, const std::string& expected_value, - std::chrono::milliseconds relative_timeout) { - auto start_time = std::chrono::steady_clock::now(); - const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time); - if (pi == nullptr) return false; - - WaitForPropertyData data; - data.expected_value = &expected_value; - data.done = false; - while (true) { - timespec ts; - // Check whether the property has the value we're looking for? - __system_property_read_callback(pi, WaitForPropertyCallback, &data); - if (data.done) return true; - - // It didn't, so wait for the property to change before checking again. - UpdateTimeSpec(ts, relative_timeout, start_time); - uint32_t unused; - if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false; - } -} - -bool WaitForPropertyCreation(const std::string& key, - std::chrono::milliseconds relative_timeout) { - auto start_time = std::chrono::steady_clock::now(); - return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr); -} - -CachedProperty::CachedProperty(const char* property_name) - : property_name_(property_name), - prop_info_(nullptr), - cached_area_serial_(0), - cached_property_serial_(0), - is_read_only_(android::base::StartsWith(property_name, "ro.")), - read_only_property_(nullptr) { - static_assert(sizeof(cached_value_) == PROP_VALUE_MAX); -} - -const char* CachedProperty::Get(bool* changed) { - std::optional initial_property_serial_ = cached_property_serial_; - - // Do we have a `struct prop_info` yet? - if (prop_info_ == nullptr) { - // `__system_property_find` is expensive, so only retry if a property - // has been created since last time we checked. - uint32_t property_area_serial = __system_property_area_serial(); - if (property_area_serial != cached_area_serial_) { - prop_info_ = __system_property_find(property_name_.c_str()); - cached_area_serial_ = property_area_serial; - } - } - - if (prop_info_ != nullptr) { - // Only bother re-reading the property if it's actually changed since last time. - uint32_t property_serial = __system_property_serial(prop_info_); - if (property_serial != cached_property_serial_) { - __system_property_read_callback( - prop_info_, - [](void* data, const char*, const char* value, uint32_t serial) { - CachedProperty* instance = reinterpret_cast(data); - instance->cached_property_serial_ = serial; - // Read only properties can be larger than PROP_VALUE_MAX, but also never change value - // or location, thus we return the pointer from the shared memory directly. - if (instance->is_read_only_) { - instance->read_only_property_ = value; - } else { - strlcpy(instance->cached_value_, value, PROP_VALUE_MAX); - } - }, - this); - } - } - - if (changed) { - *changed = cached_property_serial_ != initial_property_serial_; - } - - if (is_read_only_) { - return read_only_property_; - } else { - return cached_value_; - } -} - -#endif - -} // namespace base -} // namespace android diff --git a/base/properties_test.cpp b/base/properties_test.cpp deleted file mode 100644 index c30c41e8a..000000000 --- a/base/properties_test.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2016 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 "android-base/properties.h" - -#include - -#include -#include -#include -#include - -#if !defined(_WIN32) -using namespace std::literals; -#endif - -TEST(properties, smoke) { - android::base::SetProperty("debug.libbase.property_test", "hello"); - - std::string s = android::base::GetProperty("debug.libbase.property_test", ""); - ASSERT_EQ("hello", s); - - android::base::SetProperty("debug.libbase.property_test", "world"); - s = android::base::GetProperty("debug.libbase.property_test", ""); - ASSERT_EQ("world", s); - - s = android::base::GetProperty("this.property.does.not.exist", ""); - ASSERT_EQ("", s); - - s = android::base::GetProperty("this.property.does.not.exist", "default"); - ASSERT_EQ("default", s); -} - -TEST(properties, empty) { - // Because you can't delete a property, people "delete" them by - // setting them to the empty string. In that case we'd want to - // keep the default value (like cutils' property_get did). - android::base::SetProperty("debug.libbase.property_test", ""); - std::string s = android::base::GetProperty("debug.libbase.property_test", "default"); - ASSERT_EQ("default", s); -} - -static void CheckGetBoolProperty(bool expected, const std::string& value, bool default_value) { - android::base::SetProperty("debug.libbase.property_test", value.c_str()); - ASSERT_EQ(expected, android::base::GetBoolProperty("debug.libbase.property_test", default_value)); -} - -TEST(properties, GetBoolProperty_true) { - CheckGetBoolProperty(true, "1", false); - CheckGetBoolProperty(true, "y", false); - CheckGetBoolProperty(true, "yes", false); - CheckGetBoolProperty(true, "on", false); - CheckGetBoolProperty(true, "true", false); -} - -TEST(properties, GetBoolProperty_false) { - CheckGetBoolProperty(false, "0", true); - CheckGetBoolProperty(false, "n", true); - CheckGetBoolProperty(false, "no", true); - CheckGetBoolProperty(false, "off", true); - CheckGetBoolProperty(false, "false", true); -} - -TEST(properties, GetBoolProperty_default) { - CheckGetBoolProperty(true, "burp", true); - CheckGetBoolProperty(false, "burp", false); -} - -template void CheckGetIntProperty() { - // Positive and negative. - android::base::SetProperty("debug.libbase.property_test", "-12"); - EXPECT_EQ(T(-12), android::base::GetIntProperty("debug.libbase.property_test", 45)); - android::base::SetProperty("debug.libbase.property_test", "12"); - EXPECT_EQ(T(12), android::base::GetIntProperty("debug.libbase.property_test", 45)); - - // Default value. - android::base::SetProperty("debug.libbase.property_test", ""); - EXPECT_EQ(T(45), android::base::GetIntProperty("debug.libbase.property_test", 45)); - - // Bounds checks. - android::base::SetProperty("debug.libbase.property_test", "0"); - EXPECT_EQ(T(45), android::base::GetIntProperty("debug.libbase.property_test", 45, 1, 2)); - android::base::SetProperty("debug.libbase.property_test", "1"); - EXPECT_EQ(T(1), android::base::GetIntProperty("debug.libbase.property_test", 45, 1, 2)); - android::base::SetProperty("debug.libbase.property_test", "2"); - EXPECT_EQ(T(2), android::base::GetIntProperty("debug.libbase.property_test", 45, 1, 2)); - android::base::SetProperty("debug.libbase.property_test", "3"); - EXPECT_EQ(T(45), android::base::GetIntProperty("debug.libbase.property_test", 45, 1, 2)); -} - -template void CheckGetUintProperty() { - // Positive. - android::base::SetProperty("debug.libbase.property_test", "12"); - EXPECT_EQ(T(12), android::base::GetUintProperty("debug.libbase.property_test", 45)); - - // Default value. - android::base::SetProperty("debug.libbase.property_test", ""); - EXPECT_EQ(T(45), android::base::GetUintProperty("debug.libbase.property_test", 45)); - - // Bounds checks. - android::base::SetProperty("debug.libbase.property_test", "12"); - EXPECT_EQ(T(12), android::base::GetUintProperty("debug.libbase.property_test", 33, 22)); - android::base::SetProperty("debug.libbase.property_test", "12"); - EXPECT_EQ(T(5), android::base::GetUintProperty("debug.libbase.property_test", 5, 10)); -} - -TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty(); } -TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty(); } -TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty(); } -TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty(); } - -TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty(); } -TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty(); } -TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty(); } -TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty(); } - -TEST(properties, WaitForProperty) { -#if defined(__BIONIC__) - std::atomic flag{false}; - std::thread thread([&]() { - std::this_thread::sleep_for(100ms); - android::base::SetProperty("debug.libbase.WaitForProperty_test", "a"); - while (!flag) std::this_thread::yield(); - android::base::SetProperty("debug.libbase.WaitForProperty_test", "b"); - }); - - ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s)); - flag = true; - ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", 1s)); - thread.join(); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, WaitForProperty_timeout) { -#if defined(__BIONIC__) - auto t0 = std::chrono::steady_clock::now(); - ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_timeout_test", "a", - 200ms)); - auto t1 = std::chrono::steady_clock::now(); - - ASSERT_GE(std::chrono::duration_cast(t1 - t0), 200ms); - // Upper bounds on timing are inherently flaky, but let's try... - ASSERT_LT(std::chrono::duration_cast(t1 - t0), 600ms); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, WaitForProperty_MaxTimeout) { -#if defined(__BIONIC__) - std::atomic flag{false}; - std::thread thread([&]() { - android::base::SetProperty("debug.libbase.WaitForProperty_test", "a"); - while (!flag) std::this_thread::yield(); - std::this_thread::sleep_for(500ms); - android::base::SetProperty("debug.libbase.WaitForProperty_test", "b"); - }); - - ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s)); - flag = true; - // Test that this does not immediately return false due to overflow issues with the timeout. - ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b")); - thread.join(); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, WaitForProperty_NegativeTimeout) { -#if defined(__BIONIC__) - std::atomic flag{false}; - std::thread thread([&]() { - android::base::SetProperty("debug.libbase.WaitForProperty_test", "a"); - while (!flag) std::this_thread::yield(); - std::this_thread::sleep_for(500ms); - android::base::SetProperty("debug.libbase.WaitForProperty_test", "b"); - }); - - ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s)); - flag = true; - // Assert that this immediately returns with a negative timeout - ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms)); - thread.join(); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, WaitForPropertyCreation) { -#if defined(__BIONIC__) - std::thread thread([&]() { - std::this_thread::sleep_for(100ms); - android::base::SetProperty("debug.libbase.WaitForPropertyCreation_test", "a"); - }); - - ASSERT_TRUE(android::base::WaitForPropertyCreation( - "debug.libbase.WaitForPropertyCreation_test", 1s)); - thread.join(); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, WaitForPropertyCreation_timeout) { -#if defined(__BIONIC__) - auto t0 = std::chrono::steady_clock::now(); - ASSERT_FALSE(android::base::WaitForPropertyCreation( - "debug.libbase.WaitForPropertyCreation_timeout_test", 200ms)); - auto t1 = std::chrono::steady_clock::now(); - - ASSERT_GE(std::chrono::duration_cast(t1 - t0), 200ms); - // Upper bounds on timing are inherently flaky, but let's try... - ASSERT_LT(std::chrono::duration_cast(t1 - t0), 600ms); -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} - -TEST(properties, CachedProperty) { -#if defined(__BIONIC__) - android::base::CachedProperty cached_property("debug.libbase.CachedProperty_test"); - bool changed; - cached_property.Get(&changed); - - android::base::SetProperty("debug.libbase.CachedProperty_test", "foo"); - ASSERT_STREQ("foo", cached_property.Get(&changed)); - ASSERT_TRUE(changed); - - ASSERT_STREQ("foo", cached_property.Get(&changed)); - ASSERT_FALSE(changed); - - android::base::SetProperty("debug.libbase.CachedProperty_test", "bar"); - ASSERT_STREQ("bar", cached_property.Get(&changed)); - ASSERT_TRUE(changed); - - ASSERT_STREQ("bar", cached_property.Get(&changed)); - ASSERT_FALSE(changed); - -#else - GTEST_LOG_(INFO) << "This test does nothing on the host.\n"; -#endif -} diff --git a/base/result_test.cpp b/base/result_test.cpp deleted file mode 100644 index c0ac0fdaf..000000000 --- a/base/result_test.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/* - * 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 "android-base/result.h" - -#include "errno.h" - -#include -#include - -#include - -using namespace std::string_literals; - -namespace android { -namespace base { - -TEST(result, result_accessors) { - Result result = "success"; - ASSERT_RESULT_OK(result); - ASSERT_TRUE(result.has_value()); - - EXPECT_EQ("success", *result); - EXPECT_EQ("success", result.value()); - - EXPECT_EQ('s', result->data()[0]); -} - -TEST(result, result_accessors_rvalue) { - ASSERT_TRUE(Result("success").ok()); - ASSERT_TRUE(Result("success").has_value()); - - EXPECT_EQ("success", *Result("success")); - EXPECT_EQ("success", Result("success").value()); - - EXPECT_EQ('s', Result("success")->data()[0]); -} - -TEST(result, result_void) { - Result ok = {}; - EXPECT_RESULT_OK(ok); - ok.value(); // should not crash - ASSERT_DEATH(ok.error(), ""); - - Result fail = Error() << "failure" << 1; - EXPECT_FALSE(fail.ok()); - EXPECT_EQ("failure1", fail.error().message()); - EXPECT_EQ(0, fail.error().code()); - EXPECT_TRUE(ok != fail); - ASSERT_DEATH(fail.value(), ""); - - auto test = [](bool ok) -> Result { - if (ok) return {}; - else return Error() << "failure" << 1; - }; - EXPECT_TRUE(test(true).ok()); - EXPECT_FALSE(test(false).ok()); - test(true).value(); // should not crash - ASSERT_DEATH(test(true).error(), ""); - ASSERT_DEATH(test(false).value(), ""); - EXPECT_EQ("failure1", test(false).error().message()); -} - -TEST(result, result_error) { - Result result = Error() << "failure" << 1; - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - EXPECT_EQ(0, result.error().code()); - EXPECT_EQ("failure1", result.error().message()); -} - -TEST(result, result_error_empty) { - Result result = Error(); - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - EXPECT_EQ(0, result.error().code()); - EXPECT_EQ("", result.error().message()); -} - -TEST(result, result_error_rvalue) { - // Error() and ErrnoError() aren't actually used to create a Result object. - // Under the hood, they are an intermediate class that can be implicitly constructed into a - // Result. This is needed both to create the ostream and because Error() itself, by - // definition will not know what the type, T, of the underlying Result object that it would - // create is. - - auto MakeRvalueErrorResult = []() -> Result { return Error() << "failure" << 1; }; - ASSERT_FALSE(MakeRvalueErrorResult().ok()); - ASSERT_FALSE(MakeRvalueErrorResult().has_value()); - - EXPECT_EQ(0, MakeRvalueErrorResult().error().code()); - EXPECT_EQ("failure1", MakeRvalueErrorResult().error().message()); -} - -TEST(result, result_errno_error) { - constexpr int test_errno = 6; - errno = test_errno; - Result result = ErrnoError() << "failure" << 1; - - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - EXPECT_EQ(test_errno, result.error().code()); - EXPECT_EQ("failure1: "s + strerror(test_errno), result.error().message()); -} - -TEST(result, result_errno_error_no_text) { - constexpr int test_errno = 6; - errno = test_errno; - Result result = ErrnoError(); - - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - EXPECT_EQ(test_errno, result.error().code()); - EXPECT_EQ(strerror(test_errno), result.error().message()); -} - -TEST(result, result_error_from_other_result) { - auto error_text = "test error"s; - Result result = Error() << error_text; - - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - Result result2 = result.error(); - - ASSERT_FALSE(result2.ok()); - ASSERT_FALSE(result2.has_value()); - - EXPECT_EQ(0, result2.error().code()); - EXPECT_EQ(error_text, result2.error().message()); -} - -TEST(result, result_error_through_ostream) { - auto error_text = "test error"s; - Result result = Error() << error_text; - - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - Result result2 = Error() << result.error(); - - ASSERT_FALSE(result2.ok()); - ASSERT_FALSE(result2.has_value()); - - EXPECT_EQ(0, result2.error().code()); - EXPECT_EQ(error_text, result2.error().message()); -} - -TEST(result, result_errno_error_through_ostream) { - auto error_text = "test error"s; - constexpr int test_errno = 6; - errno = 6; - Result result = ErrnoError() << error_text; - - errno = 0; - - ASSERT_FALSE(result.ok()); - ASSERT_FALSE(result.has_value()); - - Result result2 = Error() << result.error(); - - ASSERT_FALSE(result2.ok()); - ASSERT_FALSE(result2.has_value()); - - EXPECT_EQ(test_errno, result2.error().code()); - EXPECT_EQ(error_text + ": " + strerror(test_errno), result2.error().message()); -} - -TEST(result, constructor_forwarding) { - auto result = Result(std::in_place, 5, 'a'); - - ASSERT_RESULT_OK(result); - ASSERT_TRUE(result.has_value()); - - EXPECT_EQ("aaaaa", *result); -} - -struct ConstructorTracker { - static size_t constructor_called; - static size_t copy_constructor_called; - static size_t move_constructor_called; - static size_t copy_assignment_called; - static size_t move_assignment_called; - - template - ConstructorTracker(T&& string) : string(string) { - ++constructor_called; - } - - ConstructorTracker(const ConstructorTracker& ct) { - ++copy_constructor_called; - string = ct.string; - } - ConstructorTracker(ConstructorTracker&& ct) noexcept { - ++move_constructor_called; - string = std::move(ct.string); - } - ConstructorTracker& operator=(const ConstructorTracker& ct) { - ++copy_assignment_called; - string = ct.string; - return *this; - } - ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept { - ++move_assignment_called; - string = std::move(ct.string); - return *this; - } - - std::string string; -}; - -size_t ConstructorTracker::constructor_called = 0; -size_t ConstructorTracker::copy_constructor_called = 0; -size_t ConstructorTracker::move_constructor_called = 0; -size_t ConstructorTracker::copy_assignment_called = 0; -size_t ConstructorTracker::move_assignment_called = 0; - -Result ReturnConstructorTracker(const std::string& in) { - if (in.empty()) { - return "literal string"; - } - if (in == "test2") { - return ConstructorTracker(in + in + "2"); - } - ConstructorTracker result(in + " " + in); - return result; -}; - -TEST(result, no_copy_on_return) { - // If returning parameters that may be used to implicitly construct the type T of Result, - // then those parameters are forwarded to the construction of Result. - - // If returning an prvalue or xvalue, it will be move constructed during the construction of - // Result. - - // This check ensures that that is the case, and particularly that no copy constructors - // are called. - - auto result1 = ReturnConstructorTracker(""); - ASSERT_RESULT_OK(result1); - EXPECT_EQ("literal string", result1->string); - EXPECT_EQ(1U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - auto result2 = ReturnConstructorTracker("test2"); - ASSERT_RESULT_OK(result2); - EXPECT_EQ("test2test22", result2->string); - EXPECT_EQ(2U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(1U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); - - auto result3 = ReturnConstructorTracker("test3"); - ASSERT_RESULT_OK(result3); - EXPECT_EQ("test3 test3", result3->string); - EXPECT_EQ(3U, ConstructorTracker::constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called); - EXPECT_EQ(2U, ConstructorTracker::move_constructor_called); - EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called); - EXPECT_EQ(0U, ConstructorTracker::move_assignment_called); -} - -// Below two tests require that we do not hide the move constructor with our forwarding reference -// constructor. This is done with by disabling the forwarding reference constructor if its first -// and only type is Result. -TEST(result, result_result_with_success) { - auto return_result_result_with_success = []() -> Result> { return Result(); }; - auto result = return_result_result_with_success(); - ASSERT_RESULT_OK(result); - ASSERT_RESULT_OK(*result); - - auto inner_result = result.value(); - ASSERT_RESULT_OK(inner_result); -} - -TEST(result, result_result_with_failure) { - auto return_result_result_with_error = []() -> Result> { - return Result(ResultError("failure string", 6)); - }; - auto result = return_result_result_with_error(); - ASSERT_RESULT_OK(result); - ASSERT_FALSE(result->ok()); - EXPECT_EQ("failure string", (*result).error().message()); - EXPECT_EQ(6, (*result).error().code()); -} - -// This test requires that we disable the forwarding reference constructor if Result is the -// *only* type that we are forwarding. In otherwords, if we are forwarding Result, int to -// construct a Result, then we still need the constructor. -TEST(result, result_two_parameter_constructor_same_type) { - struct TestStruct { - TestStruct(int value) : value_(value) {} - TestStruct(Result result, int value) : value_(result->value_ * value) {} - int value_; - }; - - auto return_test_struct = []() -> Result { - return Result(std::in_place, Result(std::in_place, 6), 6); - }; - - auto result = return_test_struct(); - ASSERT_RESULT_OK(result); - EXPECT_EQ(36, result->value_); -} - -TEST(result, die_on_access_failed_result) { - Result result = Error(); - ASSERT_DEATH(*result, ""); -} - -TEST(result, die_on_get_error_succesful_result) { - Result result = "success"; - ASSERT_DEATH(result.error(), ""); -} - -template -std::basic_ostream& SetErrnoToTwo(std::basic_ostream& ss) { - errno = 2; - return ss; -} - -TEST(result, preserve_errno) { - errno = 1; - int old_errno = errno; - Result result = Error() << "Failed" << SetErrnoToTwo; - ASSERT_FALSE(result.ok()); - EXPECT_EQ(old_errno, errno); - - errno = 1; - old_errno = errno; - Result result2 = ErrnoError() << "Failed" << SetErrnoToTwo; - ASSERT_FALSE(result2.ok()); - EXPECT_EQ(old_errno, errno); - EXPECT_EQ(old_errno, result2.error().code()); -} - -TEST(result, error_with_fmt) { - Result result = Errorf("{} {}!", "hello", "world"); - EXPECT_EQ("hello world!", result.error().message()); - - result = Errorf("{} {}!", std::string("hello"), std::string("world")); - EXPECT_EQ("hello world!", result.error().message()); - - result = Errorf("{1} {0}!", "world", "hello"); - EXPECT_EQ("hello world!", result.error().message()); - - result = Errorf("hello world!"); - EXPECT_EQ("hello world!", result.error().message()); - - Result result2 = Errorf("error occurred with {}", result.error()); - EXPECT_EQ("error occurred with hello world!", result2.error().message()); - - constexpr int test_errno = 6; - errno = test_errno; - result = ErrnoErrorf("{} {}!", "hello", "world"); - EXPECT_EQ(test_errno, result.error().code()); - EXPECT_EQ("hello world!: "s + strerror(test_errno), result.error().message()); -} - -TEST(result, error_with_fmt_carries_errno) { - constexpr int inner_errno = 6; - errno = inner_errno; - Result inner_result = ErrnoErrorf("inner failure"); - errno = 0; - EXPECT_EQ(inner_errno, inner_result.error().code()); - - // outer_result is created with Errorf, but its error code is got from inner_result. - Result outer_result = Errorf("outer failure caused by {}", inner_result.error()); - EXPECT_EQ(inner_errno, outer_result.error().code()); - EXPECT_EQ("outer failure caused by inner failure: "s + strerror(inner_errno), - outer_result.error().message()); - - // now both result objects are created with ErrnoErrorf. errno from the inner_result - // is not passed to outer_result. - constexpr int outer_errno = 10; - errno = outer_errno; - outer_result = ErrnoErrorf("outer failure caused by {}", inner_result.error()); - EXPECT_EQ(outer_errno, outer_result.error().code()); - EXPECT_EQ("outer failure caused by inner failure: "s + strerror(inner_errno) + ": "s + - strerror(outer_errno), - outer_result.error().message()); -} - -TEST(result, errno_chaining_multiple) { - constexpr int errno1 = 6; - errno = errno1; - Result inner1 = ErrnoErrorf("error1"); - - constexpr int errno2 = 10; - errno = errno2; - Result inner2 = ErrnoErrorf("error2"); - - // takes the error code of inner2 since its the last one. - Result outer = Errorf("two errors: {}, {}", inner1.error(), inner2.error()); - EXPECT_EQ(errno2, outer.error().code()); - EXPECT_EQ("two errors: error1: "s + strerror(errno1) + ", error2: "s + strerror(errno2), - outer.error().message()); -} - -} // namespace base -} // namespace android diff --git a/base/scopeguard_test.cpp b/base/scopeguard_test.cpp deleted file mode 100644 index 9236d7b78..000000000 --- a/base/scopeguard_test.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 "android-base/scopeguard.h" - -#include -#include - -#include - -TEST(scopeguard, normal) { - bool guarded_var = true; - { - auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; }); - } - ASSERT_FALSE(guarded_var); -} - -TEST(scopeguard, disabled) { - bool guarded_var = true; - { - auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; }); - scopeguard.Disable(); - } - ASSERT_TRUE(guarded_var); -} - -TEST(scopeguard, moved) { - int guarded_var = true; - auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; }); - { decltype(scopeguard) new_guard(std::move(scopeguard)); } - EXPECT_FALSE(scopeguard.active()); - ASSERT_FALSE(guarded_var); -} - -TEST(scopeguard, vector) { - int guarded_var = 0; - { - std::vector>> scopeguards; - scopeguards.emplace_back(android::base::make_scope_guard( - std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var)))); - scopeguards.emplace_back(android::base::make_scope_guard( - std::bind([](int& guarded_var) { guarded_var++; }, std::ref(guarded_var)))); - } - ASSERT_EQ(guarded_var, 2); -} diff --git a/base/stringprintf.cpp b/base/stringprintf.cpp deleted file mode 100644 index e83ab1316..000000000 --- a/base/stringprintf.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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 "android-base/stringprintf.h" - -#include - -#include - -namespace android { -namespace base { - -void StringAppendV(std::string* dst, const char* format, va_list ap) { - // First try with a small fixed size buffer - char space[1024] __attribute__((__uninitialized__)); - - // It's possible for methods that use a va_list to invalidate - // the data in it upon use. The fix is to make a copy - // of the structure before using it and use that copy instead. - va_list backup_ap; - va_copy(backup_ap, ap); - int result = vsnprintf(space, sizeof(space), format, backup_ap); - va_end(backup_ap); - - if (result < static_cast(sizeof(space))) { - if (result >= 0) { - // Normal case -- everything fit. - dst->append(space, result); - return; - } - - if (result < 0) { - // Just an error. - return; - } - } - - // Increase the buffer size to the size requested by vsnprintf, - // plus one for the closing \0. - int length = result + 1; - char* buf = new char[length]; - - // Restore the va_list before we use it again - va_copy(backup_ap, ap); - result = vsnprintf(buf, length, format, backup_ap); - va_end(backup_ap); - - if (result >= 0 && result < length) { - // It fit - dst->append(buf, result); - } - delete[] buf; -} - -std::string StringPrintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - std::string result; - StringAppendV(&result, fmt, ap); - va_end(ap); - return result; -} - -void StringAppendF(std::string* dst, const char* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(dst, format, ap); - va_end(ap); -} - -} // namespace base -} // namespace android diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp deleted file mode 100644 index fc009b1d7..000000000 --- a/base/stringprintf_test.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2011 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 "android-base/stringprintf.h" - -#include - -#include - -TEST(StringPrintfTest, HexSizeT) { - size_t size = 0x00107e59; - EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size)); - EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size)); -} - -TEST(StringPrintfTest, StringAppendF) { - std::string s("a"); - android::base::StringAppendF(&s, "b"); - EXPECT_EQ("ab", s); -} - -TEST(StringPrintfTest, Errno) { - errno = 123; - android::base::StringPrintf("hello %s", "world"); - EXPECT_EQ(123, errno); -} - -void TestN(size_t n) { - char* buf = new char[n + 1]; - memset(buf, 'x', n); - buf[n] = '\0'; - std::string s(android::base::StringPrintf("%s", buf)); - EXPECT_EQ(buf, s); - delete[] buf; -} - -TEST(StringPrintfTest, At1023) { - TestN(1023); -} - -TEST(StringPrintfTest, At1024) { - TestN(1024); -} - -TEST(StringPrintfTest, At1025) { - TestN(1025); -} diff --git a/base/strings.cpp b/base/strings.cpp deleted file mode 100644 index 40b2bf270..000000000 --- a/base/strings.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/strings.h" - -#include -#include - -#include -#include - -namespace android { -namespace base { - -#define CHECK_NE(a, b) \ - if ((a) == (b)) abort(); - -std::vector Split(const std::string& s, - const std::string& delimiters) { - CHECK_NE(delimiters.size(), 0U); - - std::vector result; - - size_t base = 0; - size_t found; - while (true) { - found = s.find_first_of(delimiters, base); - result.push_back(s.substr(base, found - base)); - if (found == s.npos) break; - base = found + 1; - } - - return result; -} - -std::string Trim(const std::string& s) { - std::string result; - - if (s.size() == 0) { - return result; - } - - size_t start_index = 0; - size_t end_index = s.size() - 1; - - // Skip initial whitespace. - while (start_index < s.size()) { - if (!isspace(s[start_index])) { - break; - } - start_index++; - } - - // Skip terminating whitespace. - while (end_index >= start_index) { - if (!isspace(s[end_index])) { - break; - } - end_index--; - } - - // All spaces, no beef. - if (end_index < start_index) { - return ""; - } - // Start_index is the first non-space, end_index is the last one. - return s.substr(start_index, end_index - start_index + 1); -} - -// These cases are probably the norm, so we mark them extern in the header to -// aid compile time and binary size. -template std::string Join(const std::vector&, char); -template std::string Join(const std::vector&, char); -template std::string Join(const std::vector&, const std::string&); -template std::string Join(const std::vector&, const std::string&); - -bool StartsWith(std::string_view s, std::string_view prefix) { - return s.substr(0, prefix.size()) == prefix; -} - -bool StartsWith(std::string_view s, char prefix) { - return !s.empty() && s.front() == prefix; -} - -bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) { - return s.size() >= prefix.size() && strncasecmp(s.data(), prefix.data(), prefix.size()) == 0; -} - -bool EndsWith(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix; -} - -bool EndsWith(std::string_view s, char suffix) { - return !s.empty() && s.back() == suffix; -} - -bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() && - strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(), suffix.size()) == 0; -} - -bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) { - return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0; -} - -std::string StringReplace(std::string_view s, std::string_view from, std::string_view to, - bool all) { - if (from.empty()) return std::string(s); - - std::string result; - std::string_view::size_type start_pos = 0; - do { - std::string_view::size_type pos = s.find(from, start_pos); - if (pos == std::string_view::npos) break; - - result.append(s.data() + start_pos, pos - start_pos); - result.append(to.data(), to.size()); - - start_pos = pos + from.size(); - } while (all); - result.append(s.data() + start_pos, s.size() - start_pos); - return result; -} - -} // namespace base -} // namespace android diff --git a/base/strings_test.cpp b/base/strings_test.cpp deleted file mode 100644 index 5ae309446..000000000 --- a/base/strings_test.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/strings.h" - -#include - -#include -#include -#include -#include - -TEST(strings, split_empty) { - std::vector parts = android::base::Split("", ","); - ASSERT_EQ(1U, parts.size()); - ASSERT_EQ("", parts[0]); -} - -TEST(strings, split_single) { - std::vector parts = android::base::Split("foo", ","); - ASSERT_EQ(1U, parts.size()); - ASSERT_EQ("foo", parts[0]); -} - -TEST(strings, split_simple) { - std::vector parts = android::base::Split("foo,bar,baz", ","); - ASSERT_EQ(3U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("bar", parts[1]); - ASSERT_EQ("baz", parts[2]); -} - -TEST(strings, split_with_empty_part) { - std::vector parts = android::base::Split("foo,,bar", ","); - ASSERT_EQ(3U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("", parts[1]); - ASSERT_EQ("bar", parts[2]); -} - -TEST(strings, split_with_trailing_empty_part) { - std::vector parts = android::base::Split("foo,bar,", ","); - ASSERT_EQ(3U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("bar", parts[1]); - ASSERT_EQ("", parts[2]); -} - -TEST(strings, split_null_char) { - std::vector parts = - android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1)); - ASSERT_EQ(2U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("bar", parts[1]); -} - -TEST(strings, split_any) { - std::vector parts = android::base::Split("foo:bar,baz", ",:"); - ASSERT_EQ(3U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("bar", parts[1]); - ASSERT_EQ("baz", parts[2]); -} - -TEST(strings, split_any_with_empty_part) { - std::vector parts = android::base::Split("foo:,bar", ",:"); - ASSERT_EQ(3U, parts.size()); - ASSERT_EQ("foo", parts[0]); - ASSERT_EQ("", parts[1]); - ASSERT_EQ("bar", parts[2]); -} - -TEST(strings, trim_empty) { - ASSERT_EQ("", android::base::Trim("")); -} - -TEST(strings, trim_already_trimmed) { - ASSERT_EQ("foo", android::base::Trim("foo")); -} - -TEST(strings, trim_left) { - ASSERT_EQ("foo", android::base::Trim(" foo")); -} - -TEST(strings, trim_right) { - ASSERT_EQ("foo", android::base::Trim("foo ")); -} - -TEST(strings, trim_both) { - ASSERT_EQ("foo", android::base::Trim(" foo ")); -} - -TEST(strings, trim_no_trim_middle) { - ASSERT_EQ("foo bar", android::base::Trim("foo bar")); -} - -TEST(strings, trim_other_whitespace) { - ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f")); -} - -TEST(strings, join_nothing) { - std::vector list = {}; - ASSERT_EQ("", android::base::Join(list, ',')); -} - -TEST(strings, join_single) { - std::vector list = {"foo"}; - ASSERT_EQ("foo", android::base::Join(list, ',')); -} - -TEST(strings, join_simple) { - std::vector list = {"foo", "bar", "baz"}; - ASSERT_EQ("foo,bar,baz", android::base::Join(list, ',')); -} - -TEST(strings, join_separator_in_vector) { - std::vector list = {",", ","}; - ASSERT_EQ(",,,", android::base::Join(list, ',')); -} - -TEST(strings, join_simple_ints) { - std::set list = {1, 2, 3}; - ASSERT_EQ("1,2,3", android::base::Join(list, ',')); -} - -TEST(strings, join_unordered_set) { - std::unordered_set list = {1, 2}; - ASSERT_TRUE("1,2" == android::base::Join(list, ',') || - "2,1" == android::base::Join(list, ',')); -} - -TEST(strings, StartsWith_empty) { - ASSERT_FALSE(android::base::StartsWith("", "foo")); - ASSERT_TRUE(android::base::StartsWith("", "")); -} - -TEST(strings, StartsWithIgnoreCase_empty) { - ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("", "")); -} - -TEST(strings, StartsWith_simple) { - ASSERT_TRUE(android::base::StartsWith("foo", "")); - ASSERT_TRUE(android::base::StartsWith("foo", "f")); - ASSERT_TRUE(android::base::StartsWith("foo", "fo")); - ASSERT_TRUE(android::base::StartsWith("foo", "foo")); -} - -TEST(strings, StartsWithIgnoreCase_simple) { - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo")); - ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO")); -} - -TEST(strings, StartsWith_prefix_too_long) { - ASSERT_FALSE(android::base::StartsWith("foo", "foobar")); -} - -TEST(strings, StartsWithIgnoreCase_prefix_too_long) { - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar")); - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR")); -} - -TEST(strings, StartsWith_contains_prefix) { - ASSERT_FALSE(android::base::StartsWith("foobar", "oba")); - ASSERT_FALSE(android::base::StartsWith("foobar", "bar")); -} - -TEST(strings, StartsWithIgnoreCase_contains_prefix) { - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba")); - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA")); - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar")); - ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR")); -} - -TEST(strings, StartsWith_char) { - ASSERT_FALSE(android::base::StartsWith("", 'f')); - ASSERT_TRUE(android::base::StartsWith("foo", 'f')); - ASSERT_FALSE(android::base::StartsWith("foo", 'o')); -} - -TEST(strings, EndsWith_empty) { - ASSERT_FALSE(android::base::EndsWith("", "foo")); - ASSERT_TRUE(android::base::EndsWith("", "")); -} - -TEST(strings, EndsWithIgnoreCase_empty) { - ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo")); - ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("", "")); -} - -TEST(strings, EndsWith_simple) { - ASSERT_TRUE(android::base::EndsWith("foo", "")); - ASSERT_TRUE(android::base::EndsWith("foo", "o")); - ASSERT_TRUE(android::base::EndsWith("foo", "oo")); - ASSERT_TRUE(android::base::EndsWith("foo", "foo")); -} - -TEST(strings, EndsWithIgnoreCase_simple) { - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo")); - ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO")); -} - -TEST(strings, EndsWith_prefix_too_long) { - ASSERT_FALSE(android::base::EndsWith("foo", "foobar")); -} - -TEST(strings, EndsWithIgnoreCase_prefix_too_long) { - ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar")); - ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR")); -} - -TEST(strings, EndsWith_contains_prefix) { - ASSERT_FALSE(android::base::EndsWith("foobar", "oba")); - ASSERT_FALSE(android::base::EndsWith("foobar", "foo")); -} - -TEST(strings, EndsWithIgnoreCase_contains_prefix) { - ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA")); - ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO")); -} - -TEST(strings, StartsWith_std_string) { - ASSERT_TRUE(android::base::StartsWith("hello", std::string{"hell"})); - ASSERT_FALSE(android::base::StartsWith("goodbye", std::string{"hell"})); -} - -TEST(strings, StartsWithIgnoreCase_std_string) { - ASSERT_TRUE(android::base::StartsWithIgnoreCase("HeLlO", std::string{"hell"})); - ASSERT_FALSE(android::base::StartsWithIgnoreCase("GoOdByE", std::string{"hell"})); -} - -TEST(strings, EndsWith_std_string) { - ASSERT_TRUE(android::base::EndsWith("hello", std::string{"lo"})); - ASSERT_FALSE(android::base::EndsWith("goodbye", std::string{"lo"})); -} - -TEST(strings, EndsWithIgnoreCase_std_string) { - ASSERT_TRUE(android::base::EndsWithIgnoreCase("HeLlO", std::string{"lo"})); - ASSERT_FALSE(android::base::EndsWithIgnoreCase("GoOdByE", std::string{"lo"})); -} - -TEST(strings, EndsWith_char) { - ASSERT_FALSE(android::base::EndsWith("", 'o')); - ASSERT_TRUE(android::base::EndsWith("foo", 'o')); - ASSERT_FALSE(android::base::EndsWith("foo", "f")); -} - -TEST(strings, EqualsIgnoreCase) { - ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO")); - ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo")); - ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar")); - ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool")); -} - -TEST(strings, ubsan_28729303) { - android::base::Split("/dev/null", ":"); -} - -TEST(strings, ConsumePrefix) { - std::string_view s{"foo.bar"}; - ASSERT_FALSE(android::base::ConsumePrefix(&s, "bar.")); - ASSERT_EQ("foo.bar", s); - ASSERT_TRUE(android::base::ConsumePrefix(&s, "foo.")); - ASSERT_EQ("bar", s); -} - -TEST(strings, ConsumeSuffix) { - std::string_view s{"foo.bar"}; - ASSERT_FALSE(android::base::ConsumeSuffix(&s, ".foo")); - ASSERT_EQ("foo.bar", s); - ASSERT_TRUE(android::base::ConsumeSuffix(&s, ".bar")); - ASSERT_EQ("foo", s); -} - -TEST(strings, StringReplace_false) { - // No change. - ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", false)); - ASSERT_EQ("", android::base::StringReplace("", "z", "Z", false)); - ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", false)); - - // Equal lengths. - ASSERT_EQ("Abcabc", android::base::StringReplace("abcabc", "a", "A", false)); - ASSERT_EQ("aBcabc", android::base::StringReplace("abcabc", "b", "B", false)); - ASSERT_EQ("abCabc", android::base::StringReplace("abcabc", "c", "C", false)); - - // Longer replacement. - ASSERT_EQ("foobcabc", android::base::StringReplace("abcabc", "a", "foo", false)); - ASSERT_EQ("afoocabc", android::base::StringReplace("abcabc", "b", "foo", false)); - ASSERT_EQ("abfooabc", android::base::StringReplace("abcabc", "c", "foo", false)); - - // Shorter replacement. - ASSERT_EQ("xxyz", android::base::StringReplace("abcxyz", "abc", "x", false)); - ASSERT_EQ("axyz", android::base::StringReplace("abcxyz", "bcx", "x", false)); - ASSERT_EQ("abcx", android::base::StringReplace("abcxyz", "xyz", "x", false)); -} - -TEST(strings, StringReplace_true) { - // No change. - ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "z", "Z", true)); - ASSERT_EQ("", android::base::StringReplace("", "z", "Z", true)); - ASSERT_EQ("abcabc", android::base::StringReplace("abcabc", "", "Z", true)); - - // Equal lengths. - ASSERT_EQ("AbcAbc", android::base::StringReplace("abcabc", "a", "A", true)); - ASSERT_EQ("aBcaBc", android::base::StringReplace("abcabc", "b", "B", true)); - ASSERT_EQ("abCabC", android::base::StringReplace("abcabc", "c", "C", true)); - - // Longer replacement. - ASSERT_EQ("foobcfoobc", android::base::StringReplace("abcabc", "a", "foo", true)); - ASSERT_EQ("afoocafooc", android::base::StringReplace("abcabc", "b", "foo", true)); - ASSERT_EQ("abfooabfoo", android::base::StringReplace("abcabc", "c", "foo", true)); - - // Shorter replacement. - ASSERT_EQ("xxyzx", android::base::StringReplace("abcxyzabc", "abc", "x", true)); - ASSERT_EQ("", android::base::StringReplace("", "abc", "x", true)); -} diff --git a/base/test_main.cpp b/base/test_main.cpp deleted file mode 100644 index 7fa6a8425..000000000 --- a/base/test_main.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/logging.h" - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - android::base::InitLogging(argv, android::base::StderrLogger); - return RUN_ALL_TESTS(); -} diff --git a/base/test_utils.cpp b/base/test_utils.cpp deleted file mode 100644 index 36b4cdfa4..000000000 --- a/base/test_utils.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/test_utils.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -CapturedStdFd::CapturedStdFd(int std_fd) : std_fd_(std_fd), old_fd_(-1) { - Start(); -} - -CapturedStdFd::~CapturedStdFd() { - if (old_fd_ != -1) { - Stop(); - } -} - -int CapturedStdFd::fd() const { - return temp_file_.fd; -} - -std::string CapturedStdFd::str() { - std::string result; - CHECK_EQ(0, TEMP_FAILURE_RETRY(lseek(fd(), 0, SEEK_SET))); - android::base::ReadFdToString(fd(), &result); - return result; -} - -void CapturedStdFd::Reset() { - // Do not reset while capturing. - CHECK_EQ(-1, old_fd_); - CHECK_EQ(0, TEMP_FAILURE_RETRY(lseek(fd(), 0, SEEK_SET))); - CHECK_EQ(0, ftruncate(fd(), 0)); -} - -void CapturedStdFd::Start() { -#if defined(_WIN32) - // On Windows, stderr is often buffered, so make sure it is unbuffered so - // that we can immediately read back what was written to stderr. - if (std_fd_ == STDERR_FILENO) CHECK_EQ(0, setvbuf(stderr, nullptr, _IONBF, 0)); -#endif - old_fd_ = dup(std_fd_); - CHECK_NE(-1, old_fd_); - CHECK_NE(-1, dup2(fd(), std_fd_)); -} - -void CapturedStdFd::Stop() { - CHECK_NE(-1, old_fd_); - CHECK_NE(-1, dup2(old_fd_, std_fd_)); - close(old_fd_); - old_fd_ = -1; - // Note: cannot restore prior setvbuf() setting. -} diff --git a/base/test_utils_test.cpp b/base/test_utils_test.cpp deleted file mode 100644 index 15a79dd9d..000000000 --- a/base/test_utils_test.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 "android-base/test_utils.h" - -#include -#include - -namespace android { -namespace base { - -TEST(TestUtilsTest, AssertMatch) { - ASSERT_MATCH("foobar", R"(fo+baz?r)"); - EXPECT_FATAL_FAILURE(ASSERT_MATCH("foobar", R"(foobaz)"), "regex mismatch"); -} - -TEST(TestUtilsTest, AssertNotMatch) { - ASSERT_NOT_MATCH("foobar", R"(foobaz)"); - EXPECT_FATAL_FAILURE(ASSERT_NOT_MATCH("foobar", R"(foobar)"), "regex mismatch"); -} - -TEST(TestUtilsTest, ExpectMatch) { - EXPECT_MATCH("foobar", R"(fo+baz?r)"); - EXPECT_NONFATAL_FAILURE(EXPECT_MATCH("foobar", R"(foobaz)"), "regex mismatch"); -} - -TEST(TestUtilsTest, ExpectNotMatch) { - EXPECT_NOT_MATCH("foobar", R"(foobaz)"); - EXPECT_NONFATAL_FAILURE(EXPECT_NOT_MATCH("foobar", R"(foobar)"), "regex mismatch"); -} - -TEST(TestUtilsTest, CaptureStdout_smoke) { - CapturedStdout cap; - printf("This should be captured.\n"); - cap.Stop(); - printf("This will not be captured.\n"); - ASSERT_EQ("This should be captured.\n", cap.str()); - - cap.Start(); - printf("And this text should be captured too.\n"); - cap.Stop(); - ASSERT_EQ("This should be captured.\nAnd this text should be captured too.\n", cap.str()); - - printf("Still not going to be captured.\n"); - cap.Reset(); - cap.Start(); - printf("Only this will be captured.\n"); - ASSERT_EQ("Only this will be captured.\n", cap.str()); -} - -TEST(TestUtilsTest, CaptureStderr_smoke) { - CapturedStderr cap; - fprintf(stderr, "This should be captured.\n"); - cap.Stop(); - fprintf(stderr, "This will not be captured.\n"); - ASSERT_EQ("This should be captured.\n", cap.str()); - - cap.Start(); - fprintf(stderr, "And this text should be captured too.\n"); - cap.Stop(); - ASSERT_EQ("This should be captured.\nAnd this text should be captured too.\n", cap.str()); - - fprintf(stderr, "Still not going to be captured.\n"); - cap.Reset(); - cap.Start(); - fprintf(stderr, "Only this will be captured.\n"); - ASSERT_EQ("Only this will be captured.\n", cap.str()); -} - -} // namespace base -} // namespace android diff --git a/base/threads.cpp b/base/threads.cpp deleted file mode 100644 index 48f6197ef..000000000 --- a/base/threads.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 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 - -#if defined(__APPLE__) -#include -#elif defined(__linux__) && !defined(__ANDROID__) -#include -#elif defined(_WIN32) -#include -#endif - -namespace android { -namespace base { - -uint64_t GetThreadId() { -#if defined(__BIONIC__) - return gettid(); -#elif defined(__APPLE__) - uint64_t tid; - pthread_threadid_np(NULL, &tid); - return tid; -#elif defined(__linux__) - return syscall(__NR_gettid); -#elif defined(_WIN32) - return GetCurrentThreadId(); -#endif -} - -} // namespace base -} // namespace android - -#if defined(__GLIBC__) -int tgkill(int tgid, int tid, int sig) { - return syscall(__NR_tgkill, tgid, tid, sig); -} -#endif diff --git a/base/tidy/unique_fd_test.cpp b/base/tidy/unique_fd_test.cpp deleted file mode 100644 index b3a99fcbb..000000000 --- a/base/tidy/unique_fd_test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2020 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 "android-base/unique_fd.h" - -#include - -#include - -extern void consume_unique_fd(android::base::unique_fd fd); - -TEST(unique_fd, bugprone_use_after_move) { - // Compile time test for clang-tidy's bugprone-use-after-move check. - android::base::unique_fd ufd(open("/dev/null", O_RDONLY | O_CLOEXEC)); - consume_unique_fd(std::move(ufd)); - ufd.reset(open("/dev/null", O_RDONLY | O_CLOEXEC)); - ufd.get(); - consume_unique_fd(std::move(ufd)); -} diff --git a/base/tidy/unique_fd_test2.cpp b/base/tidy/unique_fd_test2.cpp deleted file mode 100644 index b0c71e239..000000000 --- a/base/tidy/unique_fd_test2.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2020 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 "android-base/unique_fd.h" - -void consume_unique_fd(android::base::unique_fd) {} diff --git a/base/utf8.cpp b/base/utf8.cpp deleted file mode 100644 index adb46d09c..000000000 --- a/base/utf8.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2015 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 "android-base/utf8.h" - -#include -#include - -#include -#include - -#include "android-base/logging.h" - -namespace android { -namespace base { - -// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar(). -static void SetErrnoFromLastError() { - switch (GetLastError()) { - case ERROR_NO_UNICODE_TRANSLATION: - errno = EILSEQ; - break; - default: - errno = EINVAL; - break; - } -} - -bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) { - utf8->clear(); - - if (size == 0) { - return true; - } - - // TODO: Consider using std::wstring_convert once libcxx is supported on - // Windows. - - // Only Vista or later has this flag that causes WideCharToMultiByte() to - // return an error on invalid characters. - const DWORD flags = -#if (WINVER >= 0x0600) - WC_ERR_INVALID_CHARS; -#else - 0; -#endif - - const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size, - NULL, 0, NULL, NULL); - if (chars_required <= 0) { - SetErrnoFromLastError(); - return false; - } - - // This could potentially throw a std::bad_alloc exception. - utf8->resize(chars_required); - - const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size, - &(*utf8)[0], chars_required, NULL, - NULL); - if (result != chars_required) { - SetErrnoFromLastError(); - CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result - << " chars to buffer of " << chars_required << " chars"; - utf8->clear(); - return false; - } - - return true; -} - -bool WideToUTF8(const wchar_t* utf16, std::string* utf8) { - // Compute string length of NULL-terminated string with wcslen(). - return WideToUTF8(utf16, wcslen(utf16), utf8); -} - -bool WideToUTF8(const std::wstring& utf16, std::string* utf8) { - // Use the stored length of the string which allows embedded NULL characters - // to be converted. - return WideToUTF8(utf16.c_str(), utf16.length(), utf8); -} - -// Internal helper function that takes MultiByteToWideChar() flags. -static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16, - const DWORD flags) { - utf16->clear(); - - if (size == 0) { - return true; - } - - // TODO: Consider using std::wstring_convert once libcxx is supported on - // Windows. - const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size, - NULL, 0); - if (chars_required <= 0) { - SetErrnoFromLastError(); - return false; - } - - // This could potentially throw a std::bad_alloc exception. - utf16->resize(chars_required); - - const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size, - &(*utf16)[0], chars_required); - if (result != chars_required) { - SetErrnoFromLastError(); - CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result - << " chars to buffer of " << chars_required << " chars"; - utf16->clear(); - return false; - } - - return true; -} - -bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) { - // If strictly interpreting as UTF-8 succeeds, return success. - if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) { - return true; - } - - const int saved_errno = errno; - - // Fallback to non-strict interpretation, allowing invalid characters and - // converting as best as possible, and return false to signify a problem. - (void)UTF8ToWideWithFlags(utf8, size, utf16, 0); - errno = saved_errno; - return false; -} - -bool UTF8ToWide(const char* utf8, std::wstring* utf16) { - // Compute string length of NULL-terminated string with strlen(). - return UTF8ToWide(utf8, strlen(utf8), utf16); -} - -bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) { - // Use the stored length of the string which allows embedded NULL characters - // to be converted. - return UTF8ToWide(utf8.c_str(), utf8.length(), utf16); -} - -static bool isDriveLetter(wchar_t c) { - return (c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z'); -} - -bool UTF8PathToWindowsLongPath(const char* utf8, std::wstring* utf16) { - if (!UTF8ToWide(utf8, utf16)) { - return false; - } - // Note: Although most Win32 File I/O API are limited to MAX_PATH (260 - // characters), the CreateDirectory API is limited to 248 characters. - if (utf16->length() >= 248) { - // If path is of the form "x:\" or "x:/" - if (isDriveLetter((*utf16)[0]) && (*utf16)[1] == L':' && - ((*utf16)[2] == L'\\' || (*utf16)[2] == L'/')) { - // Append long path prefix, and make sure there are no unix-style - // separators to ensure a fully compliant Win32 long path string. - utf16->insert(0, LR"(\\?\)"); - std::replace(utf16->begin(), utf16->end(), L'/', L'\\'); - } - } - return true; -} - -// Versions of standard library APIs that support UTF-8 strings. -namespace utf8 { - -FILE* fopen(const char* name, const char* mode) { - std::wstring name_utf16; - if (!UTF8PathToWindowsLongPath(name, &name_utf16)) { - return nullptr; - } - - std::wstring mode_utf16; - if (!UTF8ToWide(mode, &mode_utf16)) { - return nullptr; - } - - return _wfopen(name_utf16.c_str(), mode_utf16.c_str()); -} - -int mkdir(const char* name, mode_t) { - std::wstring name_utf16; - if (!UTF8PathToWindowsLongPath(name, &name_utf16)) { - return -1; - } - - return _wmkdir(name_utf16.c_str()); -} - -int open(const char* name, int flags, ...) { - std::wstring name_utf16; - if (!UTF8PathToWindowsLongPath(name, &name_utf16)) { - return -1; - } - - int mode = 0; - if ((flags & O_CREAT) != 0) { - va_list args; - va_start(args, flags); - mode = va_arg(args, int); - va_end(args); - } - - return _wopen(name_utf16.c_str(), flags, mode); -} - -int unlink(const char* name) { - std::wstring name_utf16; - if (!UTF8PathToWindowsLongPath(name, &name_utf16)) { - return -1; - } - - return _wunlink(name_utf16.c_str()); -} - -} // namespace utf8 -} // namespace base -} // namespace android diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp deleted file mode 100644 index 472e82c63..000000000 --- a/base/utf8_test.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* -* Copyright (C) 2015 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 "android-base/utf8.h" - -#include - -#include -#include - -#include "android-base/file.h" -#include "android-base/macros.h" -#include "android-base/unique_fd.h" - -namespace android { -namespace base { - -TEST(UTFStringConversionsTest, ConvertInvalidUTF8) { - std::wstring wide; - - errno = 0; - - // Standalone \xa2 is an invalid UTF-8 sequence, so this should return an - // error. Concatenate two C/C++ literal string constants to prevent the - // compiler from giving an error about "\xa2af" containing a "hex escape - // sequence out of range". - EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide)); - - EXPECT_EQ(EILSEQ, errno); - - // Even if an invalid character is encountered, UTF8ToWide() should still do - // its best to convert the rest of the string. sysdeps_win32.cpp: - // _console_write_utf8() depends on this behavior. - // - // Thus, we verify that the valid characters are converted, but we ignore the - // specific replacement character that UTF8ToWide() may replace the invalid - // UTF-8 characters with because we want to allow that to change if the - // implementation changes. - EXPECT_EQ(0U, wide.find(L"before")); - const wchar_t after_wide[] = L"after"; - EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide)); -} - -// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc - -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// The tests below from utf_string_conversions_unittest.cc check for this -// preprocessor symbol, so define it, as it is appropriate for Windows. -#define WCHAR_T_IS_UTF16 -static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes"); - -// The tests below from utf_string_conversions_unittest.cc call versions of -// UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are -// stub implementations with that signature. These are just for testing and -// should not be moved to base because they assert/expect no errors which is -// probably not a good idea (or at least it is something that should be left -// up to the caller, not a base library). - -static std::wstring UTF8ToWide(const std::string& utf8) { - std::wstring utf16; - EXPECT_TRUE(UTF8ToWide(utf8, &utf16)); - return utf16; -} - -static std::string WideToUTF8(const std::wstring& utf16) { - std::string utf8; - EXPECT_TRUE(WideToUTF8(utf16, &utf8)); - return utf8; -} - -namespace { - -const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - -} // namespace - -TEST(UTFStringConversionsTest, ConvertUTF8AndWide) { - // we round-trip all the wide strings through UTF-8 to make sure everything - // agrees on the conversion. This uses the stream operators to test them - // simultaneously. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::ostringstream utf8; - utf8 << WideToUTF8(kConvertRoundtripCases[i]); - std::wostringstream wide; - wide << UTF8ToWide(utf8.str()); - - EXPECT_EQ(kConvertRoundtripCases[i], wide.str()); - } -} - -TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) { - // An empty std::wstring should be converted to an empty std::string, - // and vice versa. - std::wstring wempty; - std::string empty; - EXPECT_EQ(empty, WideToUTF8(wempty)); - EXPECT_EQ(wempty, UTF8ToWide(empty)); -} - -TEST(UTFStringConversionsTest, ConvertUTF8ToWide) { - struct UTF8ToWideCase { - const char* utf8; - const wchar_t* wide; - bool success; - } convert_cases[] = { - // Regular UTF-8 input. - {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true}, - // Non-character is passed through. - {"\xef\xbf\xbfHello", L"\xffffHello", true}, - // Truncated UTF-8 sequence. - {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, - // Truncated off the end. - {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false}, - // Non-shortest-form UTF-8. - {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, - // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal. - // Note that for whatever reason, this test fails on Windows XP. - {"\xed\xb0\x80", L"\xfffd", false}, - // Non-BMP characters. The second is a non-character regarded as valid. - // The result will either be in UTF-16 or UTF-32. -#if defined(WCHAR_T_IS_UTF16) - {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true}, -#elif defined(WCHAR_T_IS_UTF32) - {"A\xF0\x90\x8C\x80z", L"A\x10300z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true}, -#endif - }; - - for (size_t i = 0; i < arraysize(convert_cases); i++) { - std::wstring converted; - errno = 0; - const bool success = UTF8ToWide(convert_cases[i].utf8, - strlen(convert_cases[i].utf8), - &converted); - EXPECT_EQ(convert_cases[i].success, success); - // The original test always compared expected and converted, but don't do - // that because our implementation of UTF8ToWide() does not guarantee to - // produce the same output in error situations. - if (success) { - std::wstring expected(convert_cases[i].wide); - EXPECT_EQ(expected, converted); - } else { - EXPECT_EQ(EILSEQ, errno); - } - } - - // Manually test an embedded NULL. - std::wstring converted; - EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted)); - ASSERT_EQ(3U, converted.length()); - EXPECT_EQ(static_cast(0), converted[0]); - EXPECT_EQ('Z', converted[1]); - EXPECT_EQ('\t', converted[2]); - - // Make sure that conversion replaces, not appends. - EXPECT_TRUE(UTF8ToWide("B", 1, &converted)); - ASSERT_EQ(1U, converted.length()); - EXPECT_EQ('B', converted[0]); -} - -#if defined(WCHAR_T_IS_UTF16) -// This test is only valid when wchar_t == UTF-16. -TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf16; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular UTF-16 input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // The first character is a truncated UTF-16 character. - // Note that for whatever reason, this test fails on Windows XP. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", -#if (WINVER >= 0x0600) - // Only Vista and later has a new API/flag that correctly returns false. - false -#else - true -#endif - }, - // Truncated at the end. - // Note that for whatever reason, this test fails on Windows XP. - {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", -#if (WINVER >= 0x0600) - // Only Vista and later has a new API/flag that correctly returns false. - false -#else - true -#endif - }, - }; - - for (size_t i = 0; i < arraysize(convert_cases); i++) { - std::string converted; - errno = 0; - const bool success = WideToUTF8(convert_cases[i].utf16, - wcslen(convert_cases[i].utf16), - &converted); - EXPECT_EQ(convert_cases[i].success, success); - // The original test always compared expected and converted, but don't do - // that because our implementation of WideToUTF8() does not guarantee to - // produce the same output in error situations. - if (success) { - std::string expected(convert_cases[i].utf8); - EXPECT_EQ(expected, converted); - } else { - EXPECT_EQ(EILSEQ, errno); - } - } -} - -#elif defined(WCHAR_T_IS_UTF32) -// This test is only valid when wchar_t == UTF-32. -TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf32; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular 16-bit input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"A\x10300z", "A\xF0\x90\x8C\x80z", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // Invalid Unicode code points. - {L"\xfffffffHello", "\xEF\xBF\xBDHello", false}, - // The first character is a truncated UTF-16 character. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, - {L"\xdc01Hello", "\xef\xbf\xbdHello", false}, - }; - - for (size_t i = 0; i < arraysize(convert_cases); i++) { - std::string converted; - EXPECT_EQ(convert_cases[i].success, - WideToUTF8(convert_cases[i].utf32, - wcslen(convert_cases[i].utf32), - &converted)); - std::string expected(convert_cases[i].utf8); - EXPECT_EQ(expected, converted); - } -} -#endif // defined(WCHAR_T_IS_UTF32) - -// The test below uses these types and functions, so just do enough to get the -// test running. -typedef wchar_t char16; -typedef std::wstring string16; - -template -static void* WriteInto(T* t, size_t size) { - // std::(w)string::resize() already includes space for a NULL terminator. - t->resize(size - 1); - return &(*t)[0]; -} - -// A stub implementation that calls a helper from above, just to get the test -// below working. This is just for testing and should not be moved to base -// because this ignores errors which is probably not a good idea, plus it takes -// a string16 type which we don't really have. -static std::string UTF16ToUTF8(const string16& utf16) { - return WideToUTF8(utf16); -} - -TEST(UTFStringConversionsTest, ConvertMultiString) { - static char16 multi16[] = { - 'f', 'o', 'o', '\0', - 'b', 'a', 'r', '\0', - 'b', 'a', 'z', '\0', - '\0' - }; - static char multi[] = { - 'f', 'o', 'o', '\0', - 'b', 'a', 'r', '\0', - 'b', 'a', 'z', '\0', - '\0' - }; - string16 multistring16; - memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16, - sizeof(multi16)); - EXPECT_EQ(arraysize(multi16) - 1, multistring16.length()); - std::string expected; - memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi)); - EXPECT_EQ(arraysize(multi) - 1, expected.length()); - const std::string& converted = UTF16ToUTF8(multistring16); - EXPECT_EQ(arraysize(multi) - 1, converted.length()); - EXPECT_EQ(expected, converted); -} - -// The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8() -// and SysUTF8ToWide(), so these are stub implementations that call the helpers -// above. These are just for testing and should not be moved to base because -// they ignore errors which is probably not a good idea. - -static std::string SysWideToUTF8(const std::wstring& utf16) { - return WideToUTF8(utf16); -} - -static std::wstring SysUTF8ToWide(const std::string& utf8) { - return UTF8ToWide(utf8); -} - -// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifdef WCHAR_T_IS_UTF32 -static const std::wstring kSysWideOldItalicLetterA = L"\x10300"; -#else -static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00"; -#endif - -TEST(SysStrings, SysWideToUTF8) { - EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world")); - EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d")); - - // >16 bits - EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA)); - - // Error case. When Windows finds a UTF-16 character going off the end of - // a string, it just converts that literal value to UTF-8, even though this - // is invalid. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", - // SysWideToUTF8(L"\x4f60\xd800zyxw")); - - // Test embedded NULLs. - std::wstring wide_null(L"a"); - wide_null.push_back(0); - wide_null.push_back('b'); - - std::string expected_null("a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysWideToUTF8(wide_null)); -} - -TEST(SysStrings, SysUTF8ToWide) { - EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world")); - EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); - // >16 bits - EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80")); - - // Error case. When Windows finds an invalid UTF-8 character, it just skips - // it. This seems weird because it's inconsistent with the reverse conversion. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); - - // Test embedded NULLs. - std::string utf8_null("a"); - utf8_null.push_back(0); - utf8_null.push_back('b'); - - std::wstring expected_null(L"a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null)); -} - -TEST(UTF8PathToWindowsLongPathTest, DontAddPrefixIfShorterThanMaxPath) { - std::string utf8 = "c:\\mypath\\myfile.txt"; - - std::wstring wide; - EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); - - EXPECT_EQ(std::string::npos, wide.find(LR"(\\?\)")); -} - -TEST(UTF8PathToWindowsLongPathTest, AddPrefixIfLongerThanMaxPath) { - std::string utf8 = "c:\\mypath"; - while (utf8.length() < 300 /* MAX_PATH is 260 */) { - utf8 += "\\mypathsegment"; - } - - std::wstring wide; - EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); - - EXPECT_EQ(0U, wide.find(LR"(\\?\)")); - EXPECT_EQ(std::string::npos, wide.find(L"/")); -} - -TEST(UTF8PathToWindowsLongPathTest, AddPrefixAndFixSeparatorsIfLongerThanMaxPath) { - std::string utf8 = "c:/mypath"; - while (utf8.length() < 300 /* MAX_PATH is 260 */) { - utf8 += "/mypathsegment"; - } - - std::wstring wide; - EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); - - EXPECT_EQ(0U, wide.find(LR"(\\?\)")); - EXPECT_EQ(std::string::npos, wide.find(L"/")); -} - -namespace utf8 { - -TEST(Utf8FilesTest, CanCreateOpenAndDeleteFileWithLongPath) { - TemporaryDir td; - - // Create long directory path - std::string utf8 = td.path; - while (utf8.length() < 300 /* MAX_PATH is 260 */) { - utf8 += "\\mypathsegment"; - EXPECT_EQ(0, mkdir(utf8.c_str(), 0)); - } - - // Create file - utf8 += "\\test-file.bin"; - int flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; - int mode = 0666; - android::base::unique_fd fd(open(utf8.c_str(), flags, mode)); - EXPECT_NE(-1, fd.get()); - - // Close file - fd.reset(); - EXPECT_EQ(-1, fd.get()); - - // Open file with fopen - FILE* file = fopen(utf8.c_str(), "rb"); - EXPECT_NE(nullptr, file); - - if (file) { - fclose(file); - } - - // Delete file - EXPECT_EQ(0, unlink(utf8.c_str())); -} - -} // namespace utf8 -} // namespace base -} // namespace android