Migrate system/core/base to system/libbase.

Add Symlink to ensure hardcoded references do not break build.
BUG: 148941208
test: TH

Change-Id: Ia2b69de1af6e07be2aab3ba4fe1493de80269c40
Merged-In: I1134f1e9e968b9273748e2483bea8d25e5c9e994
This commit is contained in:
Baligh Uddin 2020-05-19 21:27:38 +00:00
parent 984aa655df
commit 28d0f1a3af
82 changed files with 1 additions and 12024 deletions

1
base Symbolic link
View File

@ -0,0 +1 @@
../libbase

View File

@ -1 +0,0 @@
../.clang-format-2

View File

@ -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",
},
},
}

View File

@ -1,2 +0,0 @@
set noparent
filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators

View File

@ -1,3 +0,0 @@
enh@google.com
jmgao@google.com
tomcherry@google.com

View File

@ -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.

View File

@ -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 <time.h>
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

View File

@ -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 <time.h>
#include <chrono>
#include <sstream>
#include <string>
#include <thread>
#include <gtest/gtest.h>
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<std::chrono::seconds>(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<std::chrono::seconds>(boot_clock::now().time_since_epoch());
EXPECT_EQ(now, boot_seconds);
}
template <typename T>
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<std::chrono::milliseconds>(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

View File

@ -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 <android-base/cmsg.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/user.h>
#include <memory>
#include <android-base/logging.h>
namespace android {
namespace base {
ssize_t SendFileDescriptorVector(borrowed_fd sockfd, const void* data, size_t len,
const std::vector<int>& 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<void*>(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<unsigned int>(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<int*>(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<unique_fd>* 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<void*>(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<unsigned int>(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<unique_fd> 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<int*>(CMSG_DATA(cmsg));
size_t cmsg_fdcount = static_cast<size_t>(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

View File

@ -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 <android-base/cmsg.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#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> {
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<unique_fd> 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<unique_fd> 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

View File

@ -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 <gtest/gtest.h>
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));
}

View File

@ -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 <gtest/gtest.h>
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

View File

@ -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 <errno.h>
#include <string.h>
namespace android {
namespace base {
std::string SystemErrorCodeToString(int error_code) {
return strerror(error_code);
}
} // namespace base
} // namespace android

View File

@ -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 <windows.h>
#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

View File

@ -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 <cstdio>
#include <memory>
#include <string>
#include <gtest/gtest.h>
using android::base::expected;
using android::base::unexpected;
typedef expected<int, int> exp_int;
typedef expected<double, double> exp_double;
typedef expected<std::string, std::string> exp_string;
typedef expected<std::pair<std::string, int>, int> exp_pair;
typedef expected<void, int> 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<T,E> 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<T, int> 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<T, int> 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<T, int> 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<int,int> e = 10;
expected<int32_t, int> e2 = 10;
EXPECT_TRUE(e == e2);
e2 = 20;
EXPECT_FALSE(e == e2);
expected<std::string_view,int> e3 = "hello";
expected<std::string,int> e4 = "hello";
EXPECT_TRUE(e3 == e4);
e4 = "world";
EXPECT_FALSE(e3 == e4);
expected<void,int> e5;
expected<int,int> 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<QR,E> {
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 <typename T,
typename std::enable_if_t<std::is_convertible_v<T, std::string>>* = 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<ConstructorTracker, int> 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<exp_string, std::string> 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<exp_string, std::string> e2 = unexpected("world");
EXPECT_FALSE(e2.has_value());
EXPECT_FALSE(e2.ok());
EXPECT_EQ("world", e2.error());
expected<exp_string, std::string> 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<const char*, int> 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<int, AssertNotConstructed> v(42);
EXPECT_TRUE(v.has_value());
EXPECT_EQ(42, v.value());
expected<AssertNotConstructed, int> e(unexpected(42));
EXPECT_FALSE(e.has_value());
EXPECT_EQ(42, e.error());
}
TEST(Expected, testWithMoveOnlyType) {
typedef expected<std::unique_ptr<int>,std::unique_ptr<int>> exp_ptr;
exp_ptr e(std::make_unique<int>(3));
exp_ptr e2(unexpected(std::make_unique<int>(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()));
}

View File

@ -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 <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif
#if defined(_WIN32)
#include <direct.h>
#include <windows.h>
#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<uint8_t*>(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<DWORD>(offset);
overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
static_cast<DWORD>(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<ssize_t>(bytes_read);
}
#endif
bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
uint8_t* p = reinterpret_cast<uint8_t*>(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<const uint8_t*>(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<char> 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_t>(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<char> 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<std::mutex> 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<std::mutex> 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

View File

@ -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 <gtest/gtest.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <wchar.h>
#include <string>
#if !defined(_WIN32)
#include <pwd.h>
#else
#include <windows.h>
#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<unsigned int>(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<size_t>(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());
}

View File

@ -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 <limits>
#include <benchmark/benchmark.h>
#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<int>::min(),
std::numeric_limits<int>::max()));
}
}
BENCHMARK(BenchmarkFormatInt);
static void BenchmarkStringPrintfInt(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(StringPrintf("%d %d %d", 42, std::numeric_limits<int>::min(),
std::numeric_limits<int>::max()));
}
}
BENCHMARK(BenchmarkStringPrintfInt);
static void BenchmarkFormatFloat(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(fmt::format("{} {} {}", 42.42, std::numeric_limits<float>::min(),
std::numeric_limits<float>::max()));
}
}
BENCHMARK(BenchmarkFormatFloat);
static void BenchmarkStringPrintfFloat(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(StringPrintf("%f %f %f", 42.42, std::numeric_limits<float>::min(),
std::numeric_limits<float>::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();

View File

@ -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 <chrono>
#include <sstream>
#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<boot_clock, duration> time_point;
static time_point now();
};
class Timer {
public:
Timer() : start_(boot_clock::now()) {}
std::chrono::milliseconds duration() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() - start_);
}
private:
boot_clock::time_point start_;
};
std::ostream& operator<<(std::ostream& os, const Timer& t);
} // namespace base
} // namespace android

View File

@ -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 <sys/stat.h>
#include <sys/types.h>
#include <type_traits>
#include <vector>
#include <android-base/collections.h>
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
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<int>& 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<android::base::unique_fd>* fds);
// Helper for SendFileDescriptorVector that constructs a std::vector for you, e.g.:
// SendFileDescriptors(sock, "foo", 3, std::move(fd1), std::move(fd2))
template <typename... Args>
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<int>(std::forward<Args>(sent_fds)...);
std::vector<int> fds;
Append(fds, std::forward<Args>(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 <typename... Args>
ssize_t ReceiveFileDescriptors(borrowed_fd sock, void* data, size_t len, Args&&... received_fds) {
std::vector<unique_fd*> fds;
Append(fds, std::forward<Args>(received_fds)...);
std::vector<unique_fd> 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

View File

@ -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 <utility>
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 <typename... Args>
// std::vector<int> CreateVector(Args&&... args) {
// std::vector<int> result;
// Append(result, std::forward<Args>(args)...);
// return result;
// }
template <typename CollectionType, typename T>
void Append(CollectionType& collection, T&& arg) {
collection.push_back(std::forward<T>(arg));
}
template <typename CollectionType, typename T, typename... Args>
void Append(CollectionType& collection, T&& arg, Args&&... args) {
collection.push_back(std::forward<T>(arg));
return Append(collection, std::forward<Args>(args)...);
}
// Assert that all of the arguments in a variadic template parameter pack are of a given type
// after std::decay.
template <typename T, typename Arg, typename... Args>
void AssertType(Arg&&) {
static_assert(std::is_same<T, typename std::decay<Arg>::type>::value);
}
template <typename T, typename Arg, typename... Args>
void AssertType(Arg&&, Args&&... args) {
static_assert(std::is_same<T, typename std::decay<Arg>::type>::value);
AssertType<T>(std::forward<Args>(args)...);
}
} // namespace base
} // namespace android

View File

@ -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 <sys/endian.h>. */
/* For __BIONIC__ and __GLIBC__ */
#include <sys/cdefs.h>
#if defined(__BIONIC__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
/* glibc's <endian.h> is like bionic's <sys/endian.h>. */
#include <endian.h>
/* glibc keeps htons and htonl in <netinet/in.h>. */
#include <netinet/in.h>
/* 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 <sys/_endian.h>
#else
/* Windows has some of the basics as well. */
#include <sys/param.h>
#include <winsock2.h>
/* 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

View File

@ -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

View File

@ -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 <string>
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

View File

@ -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 <algorithm>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <variant>
// 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<double,std::string> 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 T, class E>
class expected;
template<class E>
class unexpected;
template<class E>
unexpected(E) -> unexpected<E>;
template<class E>
class bad_expected_access;
template<>
class bad_expected_access<void>;
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<T,E> 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 T, class E>
class _NODISCARD_ expected {
public:
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template<class U>
using rebind = expected<U, error_type>;
// constructors
constexpr expected() = default;
constexpr expected(const expected& rhs) = default;
constexpr expected(expected&& rhs) noexcept = default;
template<class U, class G _ENABLE_IF(
std::is_constructible_v<T, const U&> &&
std::is_constructible_v<E, const G&> &&
!std::is_constructible_v<T, expected<U, G>&> &&
!std::is_constructible_v<T, expected<U, G>&&> &&
!std::is_constructible_v<T, const expected<U, G>&> &&
!std::is_constructible_v<T, const expected<U, G>&&> &&
!std::is_convertible_v<expected<U, G>&, T> &&
!std::is_convertible_v<expected<U, G>&&, T> &&
!std::is_convertible_v<const expected<U, G>&, T> &&
!std::is_convertible_v<const expected<U, G>&&, T> &&
!(!std::is_convertible_v<const U&, T> ||
!std::is_convertible_v<const G&, E>) /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(const expected<U, G>& rhs) {
if (rhs.has_value()) var_ = rhs.value();
else var_ = unexpected(rhs.error());
}
template<class U, class G _ENABLE_IF(
std::is_constructible_v<T, const U&> &&
std::is_constructible_v<E, const G&> &&
!std::is_constructible_v<T, expected<U, G>&> &&
!std::is_constructible_v<T, expected<U, G>&&> &&
!std::is_constructible_v<T, const expected<U, G>&> &&
!std::is_constructible_v<T, const expected<U, G>&&> &&
!std::is_convertible_v<expected<U, G>&, T> &&
!std::is_convertible_v<expected<U, G>&&, T> &&
!std::is_convertible_v<const expected<U, G>&, T> &&
!std::is_convertible_v<const expected<U, G>&&, T> &&
(!std::is_convertible_v<const U&, T> ||
!std::is_convertible_v<const G&, E>) /* explicit */
)>
constexpr explicit expected(const expected<U, G>& rhs) {
if (rhs.has_value()) var_ = rhs.value();
else var_ = unexpected(rhs.error());
}
template<class U, class G _ENABLE_IF(
std::is_constructible_v<T, const U&> &&
std::is_constructible_v<E, const G&> &&
!std::is_constructible_v<T, expected<U, G>&> &&
!std::is_constructible_v<T, expected<U, G>&&> &&
!std::is_constructible_v<T, const expected<U, G>&> &&
!std::is_constructible_v<T, const expected<U, G>&&> &&
!std::is_convertible_v<expected<U, G>&, T> &&
!std::is_convertible_v<expected<U, G>&&, T> &&
!std::is_convertible_v<const expected<U, G>&, T> &&
!std::is_convertible_v<const expected<U, G>&&, T> &&
!(!std::is_convertible_v<const U&, T> ||
!std::is_convertible_v<const G&, E>) /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(expected<U, G>&& rhs) {
if (rhs.has_value()) var_ = std::move(rhs.value());
else var_ = unexpected(std::move(rhs.error()));
}
template<class U, class G _ENABLE_IF(
std::is_constructible_v<T, const U&> &&
std::is_constructible_v<E, const G&> &&
!std::is_constructible_v<T, expected<U, G>&> &&
!std::is_constructible_v<T, expected<U, G>&&> &&
!std::is_constructible_v<T, const expected<U, G>&> &&
!std::is_constructible_v<T, const expected<U, G>&&> &&
!std::is_convertible_v<expected<U, G>&, T> &&
!std::is_convertible_v<expected<U, G>&&, T> &&
!std::is_convertible_v<const expected<U, G>&, T> &&
!std::is_convertible_v<const expected<U, G>&&, T> &&
(!std::is_convertible_v<const U&, T> ||
!std::is_convertible_v<const G&, E>) /* explicit */
)>
constexpr explicit expected(expected<U, G>&& rhs) {
if (rhs.has_value()) var_ = std::move(rhs.value());
else var_ = unexpected(std::move(rhs.error()));
}
template <class U = T _ENABLE_IF(
std::is_constructible_v<T, U&&> &&
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
!std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
!std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
std::is_convertible_v<U&&, T> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
constexpr expected(U&& v) : var_(std::in_place_index<0>, std::forward<U>(v)) {}
template <class U = T _ENABLE_IF(
std::is_constructible_v<T, U&&> &&
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
!std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
!std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
!std::is_convertible_v<U&&, T> /* explicit */
)>
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
constexpr explicit expected(U&& v) : var_(std::in_place_index<0>, T(std::forward<U>(v))) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, const G&> &&
std::is_convertible_v<const G&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(const unexpected<G>& e)
: var_(std::in_place_index<1>, e.value()) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, const G&> &&
!std::is_convertible_v<const G&, E> /* explicit */
)>
constexpr explicit expected(const unexpected<G>& e)
: var_(std::in_place_index<1>, E(e.value())) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, G&&> &&
std::is_convertible_v<G&&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(unexpected<G>&& e)
: var_(std::in_place_index<1>, std::move(e.value())) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, G&&> &&
!std::is_convertible_v<G&&, E> /* explicit */
)>
constexpr explicit expected(unexpected<G>&& e)
: var_(std::in_place_index<1>, E(std::move(e.value()))) {}
template<class... Args _ENABLE_IF(
std::is_constructible_v<T, Args&&...>
)>
constexpr explicit expected(std::in_place_t, Args&&... args)
: var_(std::in_place_index<0>, std::forward<Args>(args)...) {}
template<class U, class... Args _ENABLE_IF(
std::is_constructible_v<T, std::initializer_list<U>&, Args...>
)>
constexpr explicit expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
: var_(std::in_place_index<0>, il, std::forward<Args>(args)...) {}
template<class... Args _ENABLE_IF(
std::is_constructible_v<E, Args...>
)>
constexpr explicit expected(unexpect_t, Args&&... args)
: var_(unexpected_type(std::forward<Args>(args)...)) {}
template<class U, class... Args _ENABLE_IF(
std::is_constructible_v<E, std::initializer_list<U>&, Args...>
)>
constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
: var_(unexpected_type(il, std::forward<Args>(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<T,E> 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<T>&& std::is_nothrow_move_assignable_v<E>) = default;
template <class U = T _ENABLE_IF(
!std::is_void_v<T> &&
!std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
!std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
std::is_constructible_v<T, U> && std::is_assignable_v<T&, U> &&
std::is_nothrow_move_constructible_v<E>)>
expected& operator=(U&& rhs) {
var_ = T(std::forward<U>(rhs));
return *this;
}
template<class G = E>
expected& operator=(const unexpected<G>& rhs) {
var_ = rhs;
return *this;
}
template<class G = E _ENABLE_IF(
std::is_nothrow_move_constructible_v<G> &&
std::is_move_assignable_v<G>
)>
expected& operator=(unexpected<G>&& rhs) {
var_ = std::move(rhs);
return *this;
}
// modifiers
template<class... Args _ENABLE_IF(
std::is_nothrow_constructible_v<T, Args...>
)>
T& emplace(Args&&... args) {
expected(std::in_place, std::forward<Args>(args)...).swap(*this);
return value();
}
template<class U, class... Args _ENABLE_IF(
std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>
)>
T& emplace(std::initializer_list<U> il, Args&&... args) {
expected(std::in_place, il, std::forward<Args>(args)...).swap(*this);
return value();
}
// swap
template<typename U = T, typename = std::enable_if_t<(
std::is_swappable_v<U> &&
std::is_swappable_v<E> &&
(std::is_move_constructible_v<U> ||
std::is_move_constructible_v<E>))>>
void swap(expected& rhs) noexcept(
std::is_nothrow_move_constructible_v<T> &&
std::is_nothrow_swappable_v<T> &&
std::is_nothrow_move_constructible_v<E> &&
std::is_nothrow_swappable_v<E>) {
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<T>(var_)); }
constexpr T&& operator*() && { return std::move(std::get<T>(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<T>(var_); }
constexpr T& value() & { return std::get<T>(var_); }
constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); }
constexpr T&& value() && { return std::move(std::get<T>(var_)); }
constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
template<class U _ENABLE_IF(
std::is_copy_constructible_v<T> &&
std::is_convertible_v<U, T>
)>
constexpr T value_or(U&& v) const& {
if (has_value()) return value();
else return static_cast<T>(std::forward<U>(v));
}
template<class U _ENABLE_IF(
std::is_move_constructible_v<T> &&
std::is_convertible_v<U, T>
)>
constexpr T value_or(U&& v) && {
if (has_value()) return std::move(value());
else return static_cast<T>(std::forward<U>(v));
}
// expected equality operators
template<class T1, class E1, class T2, class E2>
friend constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y);
template<class T1, class E1, class T2, class E2>
friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
// Comparison with unexpected<E>
template<class T1, class E1, class E2>
friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
template<class T1, class E1, class E2>
friend constexpr bool operator==(const unexpected<E2>&, const expected<T1, E1>&);
template<class T1, class E1, class E2>
friend constexpr bool operator!=(const expected<T1, E1>&, const unexpected<E2>&);
template<class T1, class E1, class E2>
friend constexpr bool operator!=(const unexpected<E2>&, const expected<T1, E1>&);
// Specialized algorithms
template<class T1, class E1>
friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
private:
std::variant<value_type, unexpected_type> var_;
};
template<class T1, class E1, class T2, class E2>
constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y) {
if (x.has_value() != y.has_value()) return false;
if (!x.has_value()) return x.error() == y.error();
return *x == *y;
}
template<class T1, class E1, class T2, class E2>
constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) {
return !(x == y);
}
// Comparison with unexpected<E>
template<class T1, class E1, class E2>
constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
return !x.has_value() && (x.error() == y.value());
}
template<class T1, class E1, class E2>
constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) {
return !y.has_value() && (x.value() == y.error());
}
template<class T1, class E1, class E2>
constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) {
return x.has_value() || (x.error() != y.value());
}
template<class T1, class E1, class E2>
constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) {
return y.has_value() || (x.value() != y.error());
}
template<class E>
class _NODISCARD_ expected<void, E> {
public:
using value_type = void;
using error_type = E;
using unexpected_type = unexpected<E>;
// constructors
constexpr expected() = default;
constexpr expected(const expected& rhs) = default;
constexpr expected(expected&& rhs) noexcept = default;
template<class U, class G _ENABLE_IF(
std::is_void_v<U> &&
std::is_convertible_v<const G&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(const expected<U, G>& rhs) {
if (!rhs.has_value()) var_ = unexpected(rhs.error());
}
template<class U, class G _ENABLE_IF(
std::is_void_v<U> &&
!std::is_convertible_v<const G&, E> /* explicit */
)>
constexpr explicit expected(const expected<U, G>& rhs) {
if (!rhs.has_value()) var_ = unexpected(rhs.error());
}
template<class U, class G _ENABLE_IF(
std::is_void_v<U> &&
std::is_convertible_v<const G&&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(expected<U, G>&& rhs) {
if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
}
template<class U, class G _ENABLE_IF(
std::is_void_v<U> &&
!std::is_convertible_v<const G&&, E> /* explicit */
)>
constexpr explicit expected(expected<U, G>&& rhs) {
if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, const G&> &&
std::is_convertible_v<const G&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(const unexpected<G>& e)
: var_(std::in_place_index<1>, e.value()) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, const G&> &&
!std::is_convertible_v<const G&, E> /* explicit */
)>
constexpr explicit expected(const unexpected<G>& e)
: var_(std::in_place_index<1>, E(e.value())) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, G&&> &&
std::is_convertible_v<G&&, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr expected(unexpected<G>&& e)
: var_(std::in_place_index<1>, std::move(e.value())) {}
template<class G = E _ENABLE_IF(
std::is_constructible_v<E, G&&> &&
!std::is_convertible_v<G&&, E> /* explicit */
)>
constexpr explicit expected(unexpected<G>&& e)
: var_(std::in_place_index<1>, E(std::move(e.value()))) {}
template<class... Args _ENABLE_IF(
sizeof...(Args) == 0
)>
constexpr explicit expected(std::in_place_t, Args&&...) {}
template<class... Args _ENABLE_IF(
std::is_constructible_v<E, Args...>
)>
constexpr explicit expected(unexpect_t, Args&&... args)
: var_(unexpected_type(std::forward<Args>(args)...)) {}
template<class U, class... Args _ENABLE_IF(
std::is_constructible_v<E, std::initializer_list<U>&, Args...>
)>
constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
: var_(unexpected_type(il, std::forward<Args>(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<T,E> 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<E>) = default;
template<class G = E>
expected& operator=(const unexpected<G>& rhs) {
var_ = rhs;
return *this;
}
template<class G = E _ENABLE_IF(
std::is_nothrow_move_constructible_v<G> &&
std::is_move_assignable_v<G>
)>
expected& operator=(unexpected<G>&& rhs) {
var_ = std::move(rhs);
return *this;
}
// modifiers
void emplace() {
var_ = std::monostate();
}
// swap
template<typename = std::enable_if_t<
std::is_swappable_v<E>>
>
void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) {
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<unexpected_type>(var_).value(); }
constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
// expected equality operators
template<class E1, class E2>
friend constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y);
// Specialized algorithms
template<class T1, class E1>
friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
private:
std::variant<std::monostate, unexpected_type> var_;
};
template<class E1, class E2>
constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y) {
if (x.has_value() != y.has_value()) return false;
if (!x.has_value()) return x.error() == y.error();
return true;
}
template<class T1, class E1, class E2>
constexpr bool operator==(const expected<T1, E1>& x, const expected<void, E2>& y) {
if (x.has_value() != y.has_value()) return false;
if (!x.has_value()) return x.error() == y.error();
return false;
}
template<class E1, class T2, class E2>
constexpr bool operator==(const expected<void, E1>& x, const expected<T2, E2>& y) {
if (x.has_value() != y.has_value()) return false;
if (!x.has_value()) return x.error() == y.error();
return false;
}
template<class E>
class unexpected {
public:
// constructors
constexpr unexpected(const unexpected&) = default;
constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
template <class Err = E _ENABLE_IF(
std::is_constructible_v<E, Err> &&
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, std::in_place_t> &&
!std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, unexpected>)>
// NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
constexpr unexpected(Err&& e) : val_(std::forward<Err>(e)) {}
template<class U, class... Args _ENABLE_IF(
std::is_constructible_v<E, std::initializer_list<U>&, Args...>
)>
constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
: val_(il, std::forward<Args>(args)...) {}
template<class Err _ENABLE_IF(
std::is_constructible_v<E, Err> &&
!std::is_constructible_v<E, unexpected<Err>&> &&
!std::is_constructible_v<E, unexpected<Err>> &&
!std::is_constructible_v<E, const unexpected<Err>&> &&
!std::is_constructible_v<E, const unexpected<Err>> &&
!std::is_convertible_v<unexpected<Err>&, E> &&
!std::is_convertible_v<unexpected<Err>, E> &&
!std::is_convertible_v<const unexpected<Err>&, E> &&
!std::is_convertible_v<const unexpected<Err>, E> &&
std::is_convertible_v<Err, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr unexpected(const unexpected<Err>& rhs)
: val_(rhs.value()) {}
template<class Err _ENABLE_IF(
std::is_constructible_v<E, Err> &&
!std::is_constructible_v<E, unexpected<Err>&> &&
!std::is_constructible_v<E, unexpected<Err>> &&
!std::is_constructible_v<E, const unexpected<Err>&> &&
!std::is_constructible_v<E, const unexpected<Err>> &&
!std::is_convertible_v<unexpected<Err>&, E> &&
!std::is_convertible_v<unexpected<Err>, E> &&
!std::is_convertible_v<const unexpected<Err>&, E> &&
!std::is_convertible_v<const unexpected<Err>, E> &&
!std::is_convertible_v<Err, E> /* explicit */
)>
constexpr explicit unexpected(const unexpected<Err>& rhs)
: val_(E(rhs.value())) {}
template<class Err _ENABLE_IF(
std::is_constructible_v<E, Err> &&
!std::is_constructible_v<E, unexpected<Err>&> &&
!std::is_constructible_v<E, unexpected<Err>> &&
!std::is_constructible_v<E, const unexpected<Err>&> &&
!std::is_constructible_v<E, const unexpected<Err>> &&
!std::is_convertible_v<unexpected<Err>&, E> &&
!std::is_convertible_v<unexpected<Err>, E> &&
!std::is_convertible_v<const unexpected<Err>&, E> &&
!std::is_convertible_v<const unexpected<Err>, E> &&
std::is_convertible_v<Err, E> /* non-explicit */
)>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr unexpected(unexpected<Err>&& rhs)
: val_(std::move(rhs.value())) {}
template<class Err _ENABLE_IF(
std::is_constructible_v<E, Err> &&
!std::is_constructible_v<E, unexpected<Err>&> &&
!std::is_constructible_v<E, unexpected<Err>> &&
!std::is_constructible_v<E, const unexpected<Err>&> &&
!std::is_constructible_v<E, const unexpected<Err>> &&
!std::is_convertible_v<unexpected<Err>&, E> &&
!std::is_convertible_v<unexpected<Err>, E> &&
!std::is_convertible_v<const unexpected<Err>&, E> &&
!std::is_convertible_v<const unexpected<Err>, E> &&
!std::is_convertible_v<Err, E> /* explicit */
)>
constexpr explicit unexpected(unexpected<Err>&& 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<E>) =
default;
template<class Err = E>
constexpr unexpected& operator=(const unexpected<Err>& rhs) {
val_ = rhs.value();
return *this;
}
template<class Err = E>
constexpr unexpected& operator=(unexpected<Err>&& rhs) {
val_ = std::forward<E>(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<E>) {
std::swap(val_, other.val_);
}
template<class E1, class E2>
friend constexpr bool
operator==(const unexpected<E1>& e1, const unexpected<E2>& e2);
template<class E1, class E2>
friend constexpr bool
operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2);
template<class E1>
friend void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y)));
private:
E val_;
};
template<class E1, class E2>
constexpr bool
operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) {
return e1.value() == e2.value();
}
template<class E1, class E2>
constexpr bool
operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) {
return e1.value() != e2.value();
}
template<class E1>
void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y))) {
x.swap(y);
}
// TODO: bad_expected_access class
#undef _ENABLE_IF
#undef _NODISCARD_
} // namespace base
} // namespace android

View File

@ -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 <sys/stat.h>
#include <sys/types.h>
#include <string>
#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

View File

@ -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 <fmt/chrono.h>
#pragma clang diagnostic pop
#include <fmt/core.h>
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <fmt/printf.h>

View File

@ -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 <functional>
#include <memory>
#include <ostream>
#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<void(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*)>;
using AbortFunction = std::function<void(const char*)>;
// 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 <typename LHS, typename RHS>
struct EagerEvaluator {
constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
}
LHS lhs;
RHS rhs;
};
// Helper function for CHECK_xx.
template <typename LHS, typename RHS>
constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
return EagerEvaluator<LHS, RHS>(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<T1, T2> { \
EagerEvaluator(T1 l, T2 r) \
: lhs(reinterpret_cast<const void*>(l)), \
rhs(reinterpret_cast<const void*>(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<LogMessageData> 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<const void*>(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<const void*>(string_pointer);
}
#pragma clang diagnostic pop
} // namespace std

View File

@ -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 <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
#include <utility>
// 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 <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().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 <typename... T>
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

View File

@ -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 <sys/types.h>
#include <memory>
#include "android-base/macros.h"
#include "android-base/off64_t.h"
#include "android-base/unique_fd.h"
#if defined(_WIN32)
#include <windows.h>
#define PROT_READ 1
#define PROT_WRITE 2
using os_handle = HANDLE;
#else
#include <sys/mman.h>
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<MappedFile> 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<MappedFile> 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

View File

@ -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 <typename T>
static inline T get_unaligned(const void* address) {
T result;
memcpy(&result, address, sizeof(T));
return result;
}
template <typename T>
static inline void put_unaligned(void* address, T v) {
memcpy(address, &v, sizeof(T));
}
} // namespace base
} // namespace android

View File

@ -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 <utility>
#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<std::string> s(5, '-');
// return *s;
// }
//
// More complex initialization with a lambda:
// const std::string& GetSessionNonce() {
// static const base::NoDestructor<std::string> nonce([] {
// std::string s(16);
// crypto::RandString(s.data(), s.size());
// return s;
// }());
// return *nonce;
// }
//
// NoDestructor<T> 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<T> over:
// - A function scoped static T* or T& that is dynamically initialized.
// - A global base::LazyInstance<T>.
//
// Note that since the destructor is never run, this *will* leak memory if used
// as a stack or member variable. Furthermore, a NoDestructor<T> should never
// have global scope as that may require a static initializer.
template <typename T>
class NoDestructor {
public:
// Not constexpr; just write static constexpr T x = ...; if the value should
// be a constexpr.
template <typename... Args>
explicit NoDestructor(Args&&... args) {
new (storage_) T(std::forward<Args>(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<const T*>(storage_); }
T* get() { return reinterpret_cast<T*>(storage_); }
private:
alignas(T) char storage_[sizeof(T)];
};
} // namespace base
} // namespace android

View File

@ -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

View File

@ -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 <string_view>
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

View File

@ -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 <errno.h>
#include <stdlib.h>
#include <limits>
#include <string>
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 <typename T, T (*strtox)(const char* str, char** endptr)>
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<double>::lowest(),
double max = std::numeric_limits<double>::max()) {
return ParseFloatingPoint<double, strtod>(s, out, min, max);
}
static inline bool ParseDouble(const std::string& s, double* out,
double min = std::numeric_limits<double>::lowest(),
double max = std::numeric_limits<double>::max()) {
return ParseFloatingPoint<double, strtod>(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<float>::lowest(),
float max = std::numeric_limits<float>::max()) {
return ParseFloatingPoint<float, strtof>(s, out, min, max);
}
static inline bool ParseFloat(const std::string& s, float* out,
float min = std::numeric_limits<float>::lowest(),
float max = std::numeric_limits<float>::max()) {
return ParseFloatingPoint<float, strtof>(s.c_str(), out, min, max);
}
} // namespace base
} // namespace android

View File

@ -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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include <limits>
#include <string>
#include <type_traits>
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 <typename T>
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
bool allow_suffixes = false) {
static_assert(std::is_unsigned<T>::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<T>(result);
}
return true;
}
// TODO: string_view
template <typename T>
bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
bool allow_suffixes = false) {
return ParseUint(s.c_str(), out, max, allow_suffixes);
}
template <typename T>
bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
return ParseUint(s, out, max, true);
}
// TODO: string_view
template <typename T>
bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::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 <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
static_assert(std::is_signed<T>::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<T>(result);
}
return true;
}
// TODO: string_view
template <typename T>
bool ParseInt(const std::string& s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
return ParseInt(s.c_str(), out, min, max);
}
} // namespace base
} // namespace android

View File

@ -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 <string>
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

View File

@ -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 <dirent.h>
#include <sys/types.h>
#include <iterator>
#include <memory>
#include <vector>
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, decltype(&closedir)> dir_;
};
public:
PidIterator begin() { return opendir("/proc"); }
PidIterator end() { return nullptr; }
};
} // namespace base
} // namespace android

View File

@ -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 <sys/cdefs.h>
#include <chrono>
#include <limits>
#include <optional>
#include <string>
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 <typename T> T GetIntProperty(const std::string& key,
T default_value,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::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 <typename T> T GetUintProperty(const std::string& key,
T default_value,
T max = std::numeric_limits<T>::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<uint32_t> cached_area_serial_;
std::optional<uint32_t> cached_property_serial_;
char cached_value_[92];
bool is_read_only_;
const char* read_only_property_;
};
#endif
} // namespace base
} // namespace android

View File

@ -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<T> either contains a member of type T that can be accessed using similar semantics as
// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
// Result<T>::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<void> is the correct return type for a function that either returns successfully or
// returns an error value. Returning {} from a function that returns Result<void> is the
// correct way to indicate that a function without a return type has completed successfully.
//
// A successful Result<T> 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<T>.
//
// Error and ErrnoError are used to construct a Result<T> that has failed. The Error class takes
// an ostream as an input and are implicitly cast to a Result<T> 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<T>.
// In this case, the string that the ResultError takes is passed through the stream normally, but
// the errno is passed to the Result<T>. This can be used to pass errno from a failing C function up
// multiple callers. Note that when the outer Result<T> 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<T>. This is particularly useful if you have a
// function that return Result<T> but you have a Result<U> and want to return its error. In this
// case, you can return the .error() from the Result<U> to construct the Result<T>.
// An example of how to use these is below:
// Result<U> 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 <errno.h>
#include <sstream>
#include <string>
#include "android-base/expected.h"
#include "android-base/format.h"
namespace android {
namespace base {
struct ResultError {
template <typename T>
ResultError(T&& message, int code) : message_(std::forward<T>(message)), code_(code) {}
template <typename T>
// NOLINTNEXTLINE(google-explicit-constructor)
operator android::base::expected<T, ResultError>() {
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 <typename T>
// NOLINTNEXTLINE(google-explicit-constructor)
operator android::base::expected<T, ResultError>() {
return android::base::unexpected(ResultError(str(), errno_));
}
template <typename T>
Error& operator<<(T&& t) {
// NOLINTNEXTLINE(bugprone-suspicious-semicolon)
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, 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 <typename T, typename... Args>
friend Error ErrorfImpl(const T&& fmt, const Args&... args);
template <typename T, typename... Args>
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 <typename T, typename... Args>
inline int ErrorCode(int code, T&& t, const Args&... args) {
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError>) {
return ErrorCode(t.code(), args...);
}
return ErrorCode(code, args...);
}
template <typename T, typename... Args>
inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
}
template <typename T, typename... Args>
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 <typename T>
using Result = android::base::expected<T, ResultError>;
// 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

View File

@ -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 <utility> // 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 <typename F>
class ScopeGuard {
public:
ScopeGuard(F&& f) : f_(std::forward<F>(f)), active_(true) {}
ScopeGuard(ScopeGuard&& that) noexcept : f_(std::move(that.f_)), active_(that.active_) {
that.active_ = false;
}
template <typename Functor>
ScopeGuard(ScopeGuard<Functor>&& 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 <typename Functor>
friend class ScopeGuard;
F f_;
bool active_;
};
template <typename F>
ScopeGuard<F> make_scope_guard(F&& f) {
return ScopeGuard<F>(std::forward<F>(f));
}
} // namespace base
} // namespace android

View File

@ -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 <stdarg.h>
#include <string>
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

View File

@ -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 <sstream>
#include <string>
#include <string_view>
#include <vector>
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<std::string> 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 <typename ContainerT, typename SeparatorT>
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<std::string>&, char);
extern template std::string Join(const std::vector<const char*>&, char);
extern template std::string Join(const std::vector<std::string>&, const std::string&);
extern template std::string Join(const std::vector<const char*>&, 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

View File

@ -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 <regex>
#include <string>
#include <android-base/file.h>
#include <android-base/macros.h>
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)

View File

@ -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 <mutex>
#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<int> 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

View File

@ -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 <stdint.h>
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

View File

@ -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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <sys/socket.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
// 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 <android/fdsan.h>
#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<uint64_t>(old_addr));
uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
reinterpret_cast<uint64_t>(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<uint64_t>(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 <typename Closer>
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 <typename T = Closer>
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 <typename T = Closer>
static void tag(long, void*, void*) {
// No-op.
}
// Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
template <typename T = Closer>
static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
T::Close(fd, tag_value);
}
template <typename T = Closer>
static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
T::Close(fd);
}
};
using unique_fd = unique_fd_impl<DefaultCloser>;
#if !defined(_WIN32)
// Inline functions, so that they can be used header-only.
template <typename Closer>
inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* 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 <typename Closer>
inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
unique_fd_impl<Closer>* right) {
int sockfd[2];
if (socketpair(domain, type, protocol, sockfd) != 0) {
return false;
}
left->reset(sockfd[0]);
right->reset(sockfd[1]);
return true;
}
template <typename Closer>
inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* 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 <typename T>
/* implicit */ borrowed_fd(const unique_fd_impl<T>& 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 <typename T>
int close(const android::base::unique_fd_impl<T>&)
__attribute__((__unavailable__("close called on unique_fd")));
template <typename T>
FILE* fdopen(const android::base::unique_fd_impl<T>&, 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 <typename T>
DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
__unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
"unique_fd, or use android::base::Fdopendir to pass ownership")));

View File

@ -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 <sys/types.h>
#include <string>
#else
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
#include <fcntl.h> // open
#include <stdio.h> // fopen
#include <sys/stat.h> // mkdir
#include <unistd.h> // 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

View File

@ -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 <dlfcn.h>
#endif
namespace android {
namespace base {
#ifdef USE_DLSYM
const std::optional<LibLogFunctions>& GetLibLogFunctions() {
static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
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<decltype(LibLogFunctions::name)>(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<LibLogFunctions>& GetLibLogFunctions() {
static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
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

View File

@ -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 <optional>
#include <android/log.h>
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<LibLogFunctions>& GetLibLogFunctions();
} // namespace base
} // namespace android

View File

@ -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 <windows.h>
#endif
#include "android-base/logging.h"
#include <fcntl.h>
#include <inttypes.h>
#include <libgen.h>
#include <time.h>
// For getprogname(3) or program_invocation_short_name.
#if defined(__ANDROID__) || defined(__APPLE__)
#include <stdlib.h>
#elif defined(__GLIBC__)
#include <errno.h>
#endif
#if defined(__linux__)
#include <sys/uio.h>
#endif
#include <atomic>
#include <iostream>
#include <limits>
#include <mutex>
#include <optional>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <android/log.h>
#ifdef __ANDROID__
#include <android/set_abort_message.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/threads.h>
#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<std::recursive_mutex> 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<const char*>(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<LogFunction>(logger));
SetAborter(std::forward<AbortFunction>(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<std::string> 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<std::recursive_mutex> 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

View File

@ -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 <inttypes.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#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 <typename F, typename... Args>
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 <typename F>
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<int>(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<int, int> 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

View File

@ -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 <string>
#include <vector>
#include <android-base/strings.h>
#include <gtest/gtest.h>
namespace android {
namespace base {
void TestNewlineSplitter(const std::string& input,
const std::vector<std::string>& expected_output) {
std::vector<std::string> 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<std::string>{""});
}
TEST(logging_splitters, NewlineSplitter_BasicString) {
TestNewlineSplitter("normal string", std::vector<std::string>{"normal string"});
}
TEST(logging_splitters, NewlineSplitter_ormalBasicStringTrailingNewline) {
TestNewlineSplitter("normal string\n", std::vector<std::string>{"normal string", ""});
}
TEST(logging_splitters, NewlineSplitter_MultilineTrailing) {
TestNewlineSplitter("normal string\nsecond string\nthirdstring",
std::vector<std::string>{"normal string", "second string", "thirdstring"});
}
TEST(logging_splitters, NewlineSplitter_MultilineTrailingNewline) {
TestNewlineSplitter(
"normal string\nsecond string\nthirdstring\n",
std::vector<std::string>{"normal string", "second string", "thirdstring", ""});
}
TEST(logging_splitters, NewlineSplitter_MultilineEmbeddedNewlines) {
TestNewlineSplitter(
"normal string\n\n\nsecond string\n\nthirdstring\n",
std::vector<std::string>{"normal string", "", "", "second string", "", "thirdstring", ""});
}
void TestLogdChunkSplitter(const std::string& tag, const std::string& file,
const std::string& input,
const std::vector<std::string>& expected_output) {
std::vector<std::string> 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<std::string>{""});
}
TEST(logging_splitters, LogdChunkSplitter_BasicString) {
TestLogdChunkSplitter("tag", "", "normal string", std::vector<std::string>{"normal string"});
}
TEST(logging_splitters, LogdChunkSplitter_NormalBasicStringTrailingNewline) {
TestLogdChunkSplitter("tag", "", "normal string\n", std::vector<std::string>{"normal string\n"});
}
TEST(logging_splitters, LogdChunkSplitter_MultilineTrailing) {
TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring",
std::vector<std::string>{"normal string\nsecond string\nthirdstring"});
}
TEST(logging_splitters, LogdChunkSplitter_MultilineTrailingNewline) {
TestLogdChunkSplitter("tag", "", "normal string\nsecond string\nthirdstring\n",
std::vector<std::string>{"normal string\nsecond string\nthirdstring\n"});
}
TEST(logging_splitters, LogdChunkSplitter_MultilineEmbeddedNewlines) {
TestLogdChunkSplitter(
"tag", "", "normal string\n\n\nsecond string\n\nthirdstring\n",
std::vector<std::string>{"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<int>(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

View File

@ -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 <libgen.h>
#if defined(_WIN32)
#include <signal.h>
#endif
#include <regex>
#include <string>
#include <thread>
#include "android-base/file.h"
#include "android-base/scopeguard.h"
#include "android-base/stringprintf.h"
#include "android-base/test_utils.h"
#include <gtest/gtest.h>
#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<size_t>(android::base::severity) + 1; \
i <= static_cast<size_t>(android::base::FATAL); \
++i) { \
{ \
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
EXPECT_FALSE(WOULD_LOG(severity)) << i; \
} \
{ \
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
EXPECT_FALSE(WOULD_LOG(::android::base::severity)) << i; \
} \
} \
#define CHECK_WOULD_LOG_ENABLED(severity) \
for (size_t i = static_cast<size_t>(android::base::VERBOSE); \
i <= static_cast<size_t>(android::base::severity); \
++i) { \
{ \
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(i)); \
EXPECT_TRUE(WOULD_LOG(severity)) << i; \
} \
{ \
android::base::ScopedLogSeverity sls2(static_cast<android::base::LogSeverity>(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
}

View File

@ -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 <stdint.h>
#include <gtest/gtest.h>
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));
}

View File

@ -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 <utility>
#include <errno.h>
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> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
int prot) {
#if defined(_WIN32)
return FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
#else
return FromOsHandle(fd.get(), offset, length, prot);
#endif
}
std::unique_ptr<MappedFile> 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<MappedFile>(
new MappedFile(const_cast<char*>(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<MappedFile>(
new MappedFile(static_cast<char*>(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<MappedFile>(new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0));
}
return nullptr;
}
return std::unique_ptr<MappedFile>(new MappedFile(static_cast<char*>(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

View File

@ -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 <gtest/gtest.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#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());
}

View File

@ -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 <gtest/gtest.h>
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<Bomb> b;
if (b->get() != 123) exit(1);
}
exit(0);
}),
::testing::ExitedWithCode(0), "");
}
TEST(no_destructor, operators) {
android::base::NoDestructor<Bomb> b;
const android::base::NoDestructor<Bomb>& 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());
}

View File

@ -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 <errno.h>
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

View File

@ -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 <errno.h>
#include <gtest/gtest.h>
#include <string_view>
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(""));
}

View File

@ -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 <gtest/gtest.h>
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));
}

View File

@ -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 <errno.h>
#include <gtest/gtest.h>
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<int>("x", nullptr));
ASSERT_EQ(EINVAL, errno);
errno = 0;
ASSERT_FALSE(android::base::ParseInt<int>("123x", nullptr));
ASSERT_EQ(EINVAL, errno);
ASSERT_TRUE(android::base::ParseInt<int>("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<unsigned short>("x", nullptr));
ASSERT_EQ(EINVAL, errno);
errno = 0;
ASSERT_FALSE(android::base::ParseUint<unsigned short>("123x", nullptr));
ASSERT_EQ(EINVAL, errno);
ASSERT_TRUE(android::base::ParseUint<unsigned short>("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));
}

View File

@ -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 <algorithm>
#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<std::string> 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

View File

@ -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 <gtest/gtest.h>
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));
}

View File

@ -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

View File

@ -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 <unistd.h>
#include <gtest/gtest.h>
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
}

View File

@ -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 <sys/system_properties.h>
#include <sys/_system_properties.h>
#endif
#include <algorithm>
#include <chrono>
#include <limits>
#include <map>
#include <string>
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
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 <typename T>
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 <typename T>
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<std::string, std::string>& g_properties = *new std::map<std::string, std::string>;
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<std::string*>(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<WaitForPropertyData*>(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<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
ts.tv_sec = std::min<std::chrono::seconds::rep>(s.count(), std::numeric_limits<time_t>::max());
ts.tv_nsec = ns.count();
}
using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
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<std::chrono::milliseconds>(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<uint32_t> 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<CachedProperty*>(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

View File

@ -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 <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <string>
#include <thread>
#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 <typename T> void CheckGetIntProperty() {
// Positive and negative.
android::base::SetProperty("debug.libbase.property_test", "-12");
EXPECT_EQ(T(-12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
android::base::SetProperty("debug.libbase.property_test", "12");
EXPECT_EQ(T(12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
// Default value.
android::base::SetProperty("debug.libbase.property_test", "");
EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
// Bounds checks.
android::base::SetProperty("debug.libbase.property_test", "0");
EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
android::base::SetProperty("debug.libbase.property_test", "1");
EXPECT_EQ(T(1), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
android::base::SetProperty("debug.libbase.property_test", "2");
EXPECT_EQ(T(2), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
android::base::SetProperty("debug.libbase.property_test", "3");
EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
}
template <typename T> void CheckGetUintProperty() {
// Positive.
android::base::SetProperty("debug.libbase.property_test", "12");
EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
// Default value.
android::base::SetProperty("debug.libbase.property_test", "");
EXPECT_EQ(T(45), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
// Bounds checks.
android::base::SetProperty("debug.libbase.property_test", "12");
EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 33, 22));
android::base::SetProperty("debug.libbase.property_test", "12");
EXPECT_EQ(T(5), android::base::GetUintProperty<T>("debug.libbase.property_test", 5, 10));
}
TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty<int8_t>(); }
TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty<int16_t>(); }
TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty<int32_t>(); }
TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty<int64_t>(); }
TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
TEST(properties, WaitForProperty) {
#if defined(__BIONIC__)
std::atomic<bool> 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<std::chrono::milliseconds>(t1 - t0), 200ms);
// Upper bounds on timing are inherently flaky, but let's try...
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(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<bool> 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<bool> 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<std::chrono::milliseconds>(t1 - t0), 200ms);
// Upper bounds on timing are inherently flaky, but let's try...
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(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
}

View File

@ -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 <istream>
#include <string>
#include <gtest/gtest.h>
using namespace std::string_literals;
namespace android {
namespace base {
TEST(result, result_accessors) {
Result<std::string> 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<std::string>("success").ok());
ASSERT_TRUE(Result<std::string>("success").has_value());
EXPECT_EQ("success", *Result<std::string>("success"));
EXPECT_EQ("success", Result<std::string>("success").value());
EXPECT_EQ('s', Result<std::string>("success")->data()[0]);
}
TEST(result, result_void) {
Result<void> ok = {};
EXPECT_RESULT_OK(ok);
ok.value(); // should not crash
ASSERT_DEATH(ok.error(), "");
Result<void> 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<void> {
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<void> 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<void> 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<T> object.
// Under the hood, they are an intermediate class that can be implicitly constructed into a
// Result<T>. 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<T> object that it would
// create is.
auto MakeRvalueErrorResult = []() -> Result<void> { 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<void> 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<void> 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<void> result = Error() << error_text;
ASSERT_FALSE(result.ok());
ASSERT_FALSE(result.has_value());
Result<std::string> 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<void> result = Error() << error_text;
ASSERT_FALSE(result.ok());
ASSERT_FALSE(result.has_value());
Result<std::string> 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<void> result = ErrnoError() << error_text;
errno = 0;
ASSERT_FALSE(result.ok());
ASSERT_FALSE(result.has_value());
Result<std::string> 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::string>(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 <typename T>
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<ConstructorTracker> 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<T>,
// then those parameters are forwarded to the construction of Result<T>.
// If returning an prvalue or xvalue, it will be move constructed during the construction of
// Result<T>.
// 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<T>.
TEST(result, result_result_with_success) {
auto return_result_result_with_success = []() -> Result<Result<void>> { return Result<void>(); };
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<Result<void>> {
return Result<void>(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<T> is the
// *only* type that we are forwarding. In otherwords, if we are forwarding Result<T>, int to
// construct a Result<T>, then we still need the constructor.
TEST(result, result_two_parameter_constructor_same_type) {
struct TestStruct {
TestStruct(int value) : value_(value) {}
TestStruct(Result<TestStruct> result, int value) : value_(result->value_ * value) {}
int value_;
};
auto return_test_struct = []() -> Result<TestStruct> {
return Result<TestStruct>(std::in_place, Result<TestStruct>(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<std::string> result = Error();
ASSERT_DEATH(*result, "");
}
TEST(result, die_on_get_error_succesful_result) {
Result<std::string> result = "success";
ASSERT_DEATH(result.error(), "");
}
template <class CharT>
std::basic_ostream<CharT>& SetErrnoToTwo(std::basic_ostream<CharT>& ss) {
errno = 2;
return ss;
}
TEST(result, preserve_errno) {
errno = 1;
int old_errno = errno;
Result<int> result = Error() << "Failed" << SetErrnoToTwo<char>;
ASSERT_FALSE(result.ok());
EXPECT_EQ(old_errno, errno);
errno = 1;
old_errno = errno;
Result<int> result2 = ErrnoError() << "Failed" << SetErrnoToTwo<char>;
ASSERT_FALSE(result2.ok());
EXPECT_EQ(old_errno, errno);
EXPECT_EQ(old_errno, result2.error().code());
}
TEST(result, error_with_fmt) {
Result<int> 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<int> 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<int> 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<int> 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<int> inner1 = ErrnoErrorf("error1");
constexpr int errno2 = 10;
errno = errno2;
Result<int> inner2 = ErrnoErrorf("error2");
// takes the error code of inner2 since its the last one.
Result<int> 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

View File

@ -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 <utility>
#include <vector>
#include <gtest/gtest.h>
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<android::base::ScopeGuard<std::function<void()>>> 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);
}

View File

@ -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 <stdio.h>
#include <string>
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<int>(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

View File

@ -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 <gtest/gtest.h>
#include <string>
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);
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
namespace android {
namespace base {
#define CHECK_NE(a, b) \
if ((a) == (b)) abort();
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters) {
CHECK_NE(delimiters.size(), 0U);
std::vector<std::string> 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<std::string>&, char);
template std::string Join(const std::vector<const char*>&, char);
template std::string Join(const std::vector<std::string>&, const std::string&);
template std::string Join(const std::vector<const char*>&, 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

View File

@ -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 <gtest/gtest.h>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
TEST(strings, split_empty) {
std::vector<std::string> parts = android::base::Split("", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("", parts[0]);
}
TEST(strings, split_single) {
std::vector<std::string> parts = android::base::Split("foo", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("foo", parts[0]);
}
TEST(strings, split_simple) {
std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> list = {};
ASSERT_EQ("", android::base::Join(list, ','));
}
TEST(strings, join_single) {
std::vector<std::string> list = {"foo"};
ASSERT_EQ("foo", android::base::Join(list, ','));
}
TEST(strings, join_simple) {
std::vector<std::string> list = {"foo", "bar", "baz"};
ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
}
TEST(strings, join_separator_in_vector) {
std::vector<std::string> list = {",", ","};
ASSERT_EQ(",,,", android::base::Join(list, ','));
}
TEST(strings, join_simple_ints) {
std::set<int> list = {1, 2, 3};
ASSERT_EQ("1,2,3", android::base::Join(list, ','));
}
TEST(strings, join_unordered_set) {
std::unordered_set<int> 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("<xx>", android::base::StringReplace("<abcabc>", "abc", "x", true));
}

View File

@ -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 <gtest/gtest.h>
#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();
}

View File

@ -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 <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
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.
}

View File

@ -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 <stdio.h>
#include "android-base/test_utils.h"
#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
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

View File

@ -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 <android-base/threads.h>
#include <stdint.h>
#include <unistd.h>
#if defined(__APPLE__)
#include <pthread.h>
#elif defined(__linux__) && !defined(__ANDROID__)
#include <syscall.h>
#elif defined(_WIN32)
#include <windows.h>
#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

View File

@ -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 <utility>
#include <gtest/gtest.h>
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));
}

View File

@ -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) {}

View File

@ -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 <windows.h>
#include "android-base/utf8.h"
#include <fcntl.h>
#include <stdio.h>
#include <algorithm>
#include <string>
#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

View File

@ -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 <gtest/gtest.h>
#include <fcntl.h>
#include <stdlib.h>
#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<wchar_t>(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<typename T>
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