mirror of
https://github.com/2009scape/2009Scape-mobile.git
synced 2026-09-10 10:36:31 -06:00
Changes/Additional to crash dumper
This commit is contained in:
parent
13a63edf8a
commit
fce46f1614
37 changed files with 3866 additions and 7 deletions
|
|
@ -1,7 +1,7 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
HERE_PATH := $(LOCAL_PATH)
|
||||
|
||||
# include $(HERE_PATH)/crash_dump/libunwind/Android.mk
|
||||
include $(HERE_PATH)/crash_dump/libbase/Android.mk
|
||||
include $(HERE_PATH)/crash_dump/libbacktrace/Android.mk
|
||||
include $(HERE_PATH)/crash_dump/debuggerd/Android.mk
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ include $(BUILD_SHARED_LIBRARY)
|
|||
# LOCAL_SRC_FILES := thread_helper.cpp
|
||||
# include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# libawt_xawt without X11
|
||||
# libawt_xawt without X11, used to get Caciocavallo working
|
||||
LOCAL_PATH := $(HERE_PATH)/awt_xawt
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := awt_xawt
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ endif
|
|||
LOCAL_LDLIBS := -llog
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libbacktrace \
|
||||
libbase
|
||||
libcrashdumpbase
|
||||
|
||||
LOCAL_CLANG := true
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,8 @@ libbacktrace_src_files := \
|
|||
UnwindMap.cpp \
|
||||
UnwindPtrace.cpp \
|
||||
|
||||
libbacktrace_shared_ldlibs := -llog -lunwind
|
||||
# -lbase
|
||||
|
||||
# libbacktrace_shared_libraries := libunwind
|
||||
libbacktrace_shared_ldlibs := -llog
|
||||
libbacktrace_shared_libraries := libunwind libcrashdumpbase
|
||||
|
||||
module := libbacktrace
|
||||
module_tag := optional
|
||||
|
|
|
|||
11
app/src/main/jni/crash_dump/libbase/.clang-format
Normal file
11
app/src/main/jni/crash_dump/libbase/.clang-format
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
BasedOnStyle: Google
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 2
|
||||
PointerAlignment: Left
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
PenaltyExcessCharacter: 32
|
||||
59
app/src/main/jni/crash_dump/libbase/Android.mk
Normal file
59
app/src/main/jni/crash_dump/libbase/Android.mk
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
libbase_src_files := \
|
||||
file.cpp \
|
||||
logging.cpp \
|
||||
parsenetaddress.cpp \
|
||||
stringprintf.cpp \
|
||||
strings.cpp \
|
||||
test_utils.cpp \
|
||||
|
||||
libbase_cppflags := \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
|
||||
libbase_linux_cppflags := \
|
||||
-Wexit-time-destructors \
|
||||
|
||||
libbase_darwin_cppflags := \
|
||||
-Wexit-time-destructors \
|
||||
|
||||
# Device
|
||||
# ------------------------------------------------------------------------------
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcrashdumpbase
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_SRC_FILES := $(libbase_src_files) $(libbase_linux_src_files)
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||
LOCAL_STATIC_LIBRARIES := liblog
|
||||
LOCAL_MULTILIB := both
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcrashdumpbase
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libcrashdumpbase
|
||||
LOCAL_SHARED_LIBRARIES := liblog
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||
LOCAL_MULTILIB := both
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
2
app/src/main/jni/crash_dump/libbase/CPPLINT.cfg
Normal file
2
app/src/main/jni/crash_dump/libbase/CPPLINT.cfg
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
set noparent
|
||||
filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators
|
||||
34
app/src/main/jni/crash_dump/libbase/errors_test.cpp
Normal file
34
app/src/main/jni/crash_dump/libbase/errors_test.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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
|
||||
29
app/src/main/jni/crash_dump/libbase/errors_unix.cpp
Normal file
29
app/src/main/jni/crash_dump/libbase/errors_unix.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
std::string SystemErrorCodeToString(int error_code) {
|
||||
return strerror(error_code);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
68
app/src/main/jni/crash_dump/libbase/errors_windows.cpp
Normal file
68
app/src/main/jni/crash_dump/libbase/errors_windows.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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
|
||||
176
app/src/main/jni/crash_dump/libbase/file.cpp
Normal file
176
app/src/main/jni/crash_dump/libbase/file.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* 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 <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
|
||||
#include "android-base/utf8.h"
|
||||
#define LOG_TAG "base.file"
|
||||
#include "cutils/log.h"
|
||||
#include "utils/Compat.h"
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
// Versions of standard library APIs that support UTF-8 strings.
|
||||
using namespace android::base::utf8;
|
||||
|
||||
bool ReadFdToString(int fd, std::string* content) {
|
||||
content->clear();
|
||||
|
||||
char buf[BUFSIZ];
|
||||
ssize_t n;
|
||||
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
|
||||
content->append(buf, n);
|
||||
}
|
||||
return (n == 0) ? true : false;
|
||||
}
|
||||
|
||||
bool ReadFileToString(const std::string& path, std::string* content) {
|
||||
content->clear();
|
||||
|
||||
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
bool result = ReadFdToString(fd, content);
|
||||
close(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WriteStringToFd(const std::string& content, int fd) {
|
||||
const char* p = content.data();
|
||||
size_t left = content.size();
|
||||
while (left > 0) {
|
||||
ssize_t n = TEMP_FAILURE_RETRY(write(fd, 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) {
|
||||
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
|
||||
if (fd == -1) {
|
||||
ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
|
||||
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) {
|
||||
ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
|
||||
return CleanUpAfterFailedWrite(path);
|
||||
}
|
||||
if (fchown(fd, owner, group) == -1) {
|
||||
ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
|
||||
return CleanUpAfterFailedWrite(path);
|
||||
}
|
||||
if (!WriteStringToFd(content, fd)) {
|
||||
ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
|
||||
return CleanUpAfterFailedWrite(path);
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool WriteStringToFile(const std::string& content, const std::string& path) {
|
||||
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
|
||||
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = WriteStringToFd(content, fd);
|
||||
close(fd);
|
||||
return result || CleanUpAfterFailedWrite(path);
|
||||
}
|
||||
|
||||
bool ReadFully(int 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, p, remaining));
|
||||
if (n <= 0) return false;
|
||||
p += n;
|
||||
remaining -= n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteFully(int 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, 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 symbol link 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 == 0) {
|
||||
if (!file_type_removable) {
|
||||
if (err != nullptr) {
|
||||
*err = "is not a regular or symbol link file";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (unlink(path.c_str()) == -1) {
|
||||
if (err != nullptr) {
|
||||
*err = strerror(errno);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
112
app/src/main/jni/crash_dump/libbase/file_test.cpp
Normal file
112
app/src/main/jni/crash_dump/libbase/file_test.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "android-base/test_utils.h"
|
||||
|
||||
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_TRUE(tf.fd != -1);
|
||||
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);
|
||||
}
|
||||
|
||||
// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
|
||||
// sense on Windows.
|
||||
#if !defined(_WIN32)
|
||||
TEST(file, WriteStringToFile2) {
|
||||
TemporaryFile tf;
|
||||
ASSERT_TRUE(tf.fd != -1);
|
||||
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
|
||||
|
||||
TEST(file, WriteStringToFd) {
|
||||
TemporaryFile tf;
|
||||
ASSERT_TRUE(tf.fd != -1);
|
||||
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_TRUE(tf.fd != -1);
|
||||
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, RemoveFileIfExist) {
|
||||
TemporaryFile tf;
|
||||
ASSERT_TRUE(tf.fd != -1);
|
||||
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 or symbol link file", err);
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.
|
||||
|
||||
#ifndef ANDROID_BASE_ERRORS_H
|
||||
#define ANDROID_BASE_ERRORS_H
|
||||
|
||||
#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
|
||||
|
||||
#endif // ANDROID_BASE_ERRORS_H
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_FILE_H
|
||||
#define ANDROID_BASE_FILE_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
|
||||
#if !defined(_WIN32) && !defined(O_BINARY)
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
bool ReadFdToString(int fd, std::string* content);
|
||||
bool ReadFileToString(const std::string& path, std::string* content);
|
||||
|
||||
bool WriteStringToFile(const std::string& content, const std::string& path);
|
||||
bool WriteStringToFd(const std::string& content, int fd);
|
||||
|
||||
#if !defined(_WIN32)
|
||||
bool WriteStringToFile(const std::string& content, const std::string& path,
|
||||
mode_t mode, uid_t owner, gid_t group);
|
||||
#endif
|
||||
|
||||
bool ReadFully(int fd, void* data, size_t byte_count);
|
||||
bool WriteFully(int fd, const void* data, size_t byte_count);
|
||||
|
||||
bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_FILE_H
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_LOGGING_H
|
||||
#define ANDROID_BASE_LOGGING_H
|
||||
|
||||
// NOTE: For Windows, you must include logging.h after windows.h to allow the
|
||||
// following code to suppress the evil ERROR macro:
|
||||
#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/macros.h"
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
enum LogSeverity {
|
||||
VERBOSE,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
FATAL,
|
||||
};
|
||||
|
||||
enum LogId {
|
||||
DEFAULT,
|
||||
MAIN,
|
||||
SYSTEM,
|
||||
};
|
||||
|
||||
typedef std::function<void(LogId, LogSeverity, const char*, const char*,
|
||||
unsigned int, const char*)> LogFunction;
|
||||
|
||||
extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
|
||||
unsigned int, const char*);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// We expose this even though it is the default because a user that wants to
|
||||
// override the default log buffer will have to construct this themselves.
|
||||
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_;
|
||||
};
|
||||
#endif
|
||||
|
||||
// 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.
|
||||
extern void InitLogging(char* argv[], LogFunction&& logger);
|
||||
|
||||
// Configures logging using the default logger (logd for the device, stderr for
|
||||
// the host).
|
||||
extern void InitLogging(char* argv[]);
|
||||
|
||||
// Replace the current logger.
|
||||
extern void SetLogger(LogFunction&& logger);
|
||||
|
||||
// Get the minimum severity level for logging.
|
||||
extern LogSeverity GetMinimumLogSeverity();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
// 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) LOG_TO(DEFAULT, severity)
|
||||
|
||||
// Logs a message to logcat with the specified log ID on Android otherwise to
|
||||
// stderr. If the severity is FATAL it also causes an abort.
|
||||
// Use an if-else statement instead of just an if statement here. So if there is a
|
||||
// else statement after LOG() macro, it won't bind to the if statement in the macro.
|
||||
// do-while(0) statement doesn't work here. Because we need to support << operator
|
||||
// following the macro, like "LOG(DEBUG) << xxx;".
|
||||
#define LOG_TO(dest, severity) \
|
||||
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
|
||||
::android::base::ErrnoRestorer() && \
|
||||
::android::base::LogMessage(__FILE__, __LINE__, \
|
||||
::android::base::dest, \
|
||||
::android::base::severity, -1).stream()
|
||||
|
||||
// A variant of LOG that also logs the current errno value. To be used when
|
||||
// library calls fail.
|
||||
#define PLOG(severity) PLOG_TO(DEFAULT, severity)
|
||||
|
||||
// Behaves like PLOG, but logs to the specified log ID.
|
||||
#define PLOG_TO(dest, severity) \
|
||||
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
|
||||
::android::base::ErrnoRestorer() && \
|
||||
::android::base::LogMessage(__FILE__, __LINE__, \
|
||||
::android::base::dest, \
|
||||
::android::base::severity, 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)) || \
|
||||
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
|
||||
::android::base::FATAL, -1).stream() \
|
||||
<< "Check failed: " #x << " "
|
||||
|
||||
// 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 */) \
|
||||
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
|
||||
::android::base::FATAL, -1).stream() \
|
||||
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS \
|
||||
<< " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
|
||||
|
||||
// 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, > )
|
||||
|
||||
// Helper for CHECK_STRxx(s1,s2) macros.
|
||||
#define CHECK_STROP(s1, s2, sense) \
|
||||
if (LIKELY((strcmp(s1, s2) == 0) == sense)) \
|
||||
; \
|
||||
else \
|
||||
LOG(FATAL) << "Check failed: " \
|
||||
<< "\"" << s1 << "\"" \
|
||||
<< (sense ? " == " : " != ") << "\"" << s2 << "\""
|
||||
|
||||
// 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; \
|
||||
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)
|
||||
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)
|
||||
#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 {
|
||||
EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
|
||||
}
|
||||
LHS lhs;
|
||||
RHS rhs;
|
||||
};
|
||||
|
||||
// Helper function for CHECK_xx.
|
||||
template <typename LHS, typename RHS>
|
||||
static inline 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:
|
||||
LogMessage(const char* file, unsigned int line, LogId id,
|
||||
LogSeverity severity, 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, LogId id,
|
||||
LogSeverity severity, const char* msg);
|
||||
|
||||
private:
|
||||
const std::unique_ptr<LogMessageData> data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LogMessage);
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
#endif // ANDROID_BASE_LOGGING_H
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_MACROS_H
|
||||
#define ANDROID_BASE_MACROS_H
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <unistd.h> // for TEMP_FAILURE_RETRY
|
||||
|
||||
// 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.
|
||||
//
|
||||
// When building with C++11 toolchains, just use the language support
|
||||
// for explicitly deleted methods.
|
||||
#if __cplusplus >= 201103L
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&) = delete; \
|
||||
void operator=(const TypeName&) = delete
|
||||
#else
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
#endif
|
||||
|
||||
// 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(); \
|
||||
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)))
|
||||
|
||||
// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
|
||||
// but can be used on anonymous types or types defined inside
|
||||
// functions. It's less safe than arraysize as it accepts some
|
||||
// (although not all) pointers. Therefore, you should use arraysize
|
||||
// whenever possible.
|
||||
//
|
||||
// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
|
||||
// size_t.
|
||||
//
|
||||
// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
|
||||
//
|
||||
// "warning: division by zero in ..."
|
||||
//
|
||||
// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
|
||||
// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
|
||||
//
|
||||
// The following comments are on the implementation details, and can
|
||||
// be ignored by the users.
|
||||
//
|
||||
// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
|
||||
// the array) and sizeof(*(arr)) (the # of bytes in one array
|
||||
// element). If the former is divisible by the latter, perhaps arr is
|
||||
// indeed an array, in which case the division result is the # of
|
||||
// elements in the array. Otherwise, arr cannot possibly be an array,
|
||||
// and we generate a compiler error to prevent the code from
|
||||
// compiling.
|
||||
//
|
||||
// Since the size of bool is implementation-defined, we need to cast
|
||||
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
|
||||
// result has type size_t.
|
||||
//
|
||||
// This macro is not perfect as it wrongfully accepts certain
|
||||
// pointers, namely where the pointer size is divisible by the pointee
|
||||
// size. Since all our code has to go through a 32-bit compiler,
|
||||
// where a pointer is 4 bytes, this means all pointers to a type whose
|
||||
// size is 3 or greater than 4 will be (righteously) rejected.
|
||||
#define ARRAYSIZE_UNSAFE(a) \
|
||||
((sizeof(a) / sizeof(*(a))) / \
|
||||
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
#define LIKELY(x) __builtin_expect((x), true)
|
||||
#define UNLIKELY(x) __builtin_expect((x), 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 in C++11 mode, 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.
|
||||
#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
|
||||
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef FALLTHROUGH_INTENDED
|
||||
#define FALLTHROUGH_INTENDED \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif // ANDROID_BASE_MACROS_H
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_MEMORY_H
|
||||
#define ANDROID_BASE_MEMORY_H
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
// Use packed structures 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 T* address) {
|
||||
struct unaligned {
|
||||
T v;
|
||||
} __attribute__((packed));
|
||||
const unaligned* p = reinterpret_cast<const unaligned*>(address);
|
||||
return p->v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void put_unaligned(T* address, T v) {
|
||||
struct unaligned {
|
||||
T v;
|
||||
} __attribute__((packed));
|
||||
unaligned* p = reinterpret_cast<unaligned*>(address);
|
||||
p->v = v;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_MEMORY_H
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_PARSEINT_H
|
||||
#define ANDROID_BASE_PARSEINT_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
// Parses the unsigned decimal integer in the string 's' and sets 'out' to
|
||||
// that value. Optionally allows the caller to define a 'max' beyond which
|
||||
// otherwise valid values will be rejected. Returns boolean success.
|
||||
template <typename T>
|
||||
bool ParseUint(const char* s, T* out,
|
||||
T max = std::numeric_limits<T>::max()) {
|
||||
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
|
||||
errno = 0;
|
||||
char* end;
|
||||
unsigned long long int result = strtoull(s, &end, base);
|
||||
if (errno != 0 || s == end || *end != '\0') {
|
||||
return false;
|
||||
}
|
||||
if (max < result) {
|
||||
return false;
|
||||
}
|
||||
*out = static_cast<T>(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parses the signed decimal integer in the string 's' and sets 'out' to
|
||||
// that value. Optionally allows the caller to define a 'min' and 'max
|
||||
// beyond which otherwise valid values will be rejected. Returns boolean
|
||||
// success.
|
||||
template <typename T>
|
||||
bool ParseInt(const char* s, T* out,
|
||||
T min = std::numeric_limits<T>::min(),
|
||||
T max = std::numeric_limits<T>::max()) {
|
||||
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
|
||||
errno = 0;
|
||||
char* end;
|
||||
long long int result = strtoll(s, &end, base);
|
||||
if (errno != 0 || s == end || *end != '\0') {
|
||||
return false;
|
||||
}
|
||||
if (result < min || max < result) {
|
||||
return false;
|
||||
}
|
||||
*out = static_cast<T>(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_PARSEINT_H
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_PARSENETADDRESS_H
|
||||
#define ANDROID_BASE_PARSENETADDRESS_H
|
||||
|
||||
#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
|
||||
|
||||
#endif // ANDROID_BASE_PARSENETADDRESS_H
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_STRINGPRINTF_H
|
||||
#define ANDROID_BASE_STRINGPRINTF_H
|
||||
|
||||
#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. On Windows,
|
||||
// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
|
||||
// in %zd and PRIu64 (and related) to be recognized by the compile-time
|
||||
// checking.
|
||||
#define FORMAT_ARCHETYPE __printf__
|
||||
#ifdef __USE_MINGW_ANSI_STDIO
|
||||
#if __USE_MINGW_ANSI_STDIO
|
||||
#undef FORMAT_ARCHETYPE
|
||||
#define FORMAT_ARCHETYPE gnu_printf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Returns a string corresponding to printf-like formatting of the arguments.
|
||||
std::string StringPrintf(const char* fmt, ...)
|
||||
__attribute__((__format__(FORMAT_ARCHETYPE, 1, 2)));
|
||||
|
||||
// Appends a printf-like formatting of the arguments to 'dst'.
|
||||
void StringAppendF(std::string* dst, const char* fmt, ...)
|
||||
__attribute__((__format__(FORMAT_ARCHETYPE, 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__(FORMAT_ARCHETYPE, 2, 0)));
|
||||
|
||||
#undef FORMAT_ARCHETYPE
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_STRINGPRINTF_H
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_STRINGS_H
|
||||
#define ANDROID_BASE_STRINGS_H
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#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(const std::string& s, const char* prefix);
|
||||
|
||||
// Tests whether 's' ends with 'suffix'.
|
||||
bool EndsWith(const std::string& s, const char* suffix);
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_STRINGS_H
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_TEST_UTILS_H
|
||||
#define ANDROID_BASE_TEST_UTILS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
|
||||
class TemporaryFile {
|
||||
public:
|
||||
TemporaryFile();
|
||||
~TemporaryFile();
|
||||
|
||||
int fd;
|
||||
char path[1024];
|
||||
|
||||
private:
|
||||
void init(const std::string& tmp_dir);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
|
||||
};
|
||||
|
||||
class TemporaryDir {
|
||||
public:
|
||||
TemporaryDir();
|
||||
~TemporaryDir();
|
||||
|
||||
char path[1024];
|
||||
|
||||
private:
|
||||
bool init(const std::string& tmp_dir);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
|
||||
};
|
||||
|
||||
#endif // ANDROID_BASE_TEST_UTILS_H
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_THREAD_ANNOTATIONS_H
|
||||
#define ANDROID_BASE_THREAD_ANNOTATIONS_H
|
||||
|
||||
#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define SCOPED_CAPABILITY \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define PT_GUARDED_BY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#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 NO_THREAD_SAFETY_ANALYSIS \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#endif // ANDROID_BASE_THREAD_ANNOTATIONS_H
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_UNIQUE_FD_H
|
||||
#define ANDROID_BASE_UNIQUE_FD_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.
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
struct DefaultCloser {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Closer>
|
||||
class unique_fd_impl final {
|
||||
public:
|
||||
unique_fd_impl() : value_(-1) {}
|
||||
|
||||
explicit unique_fd_impl(int value) : value_(value) {}
|
||||
~unique_fd_impl() { clear(); }
|
||||
|
||||
unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
|
||||
unique_fd_impl& operator=(unique_fd_impl&& s) {
|
||||
reset(s.release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset(int new_value) {
|
||||
if (value_ != -1) {
|
||||
Closer::Close(value_);
|
||||
}
|
||||
value_ = new_value;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
reset(-1);
|
||||
}
|
||||
|
||||
int get() const { return value_; }
|
||||
operator int() const { return get(); }
|
||||
|
||||
int release() __attribute__((warn_unused_result)) {
|
||||
int ret = value_;
|
||||
value_ = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_;
|
||||
|
||||
unique_fd_impl(const unique_fd_impl&);
|
||||
void operator=(const unique_fd_impl&);
|
||||
};
|
||||
|
||||
using unique_fd = unique_fd_impl<DefaultCloser>;
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_UNIQUE_FD_H
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_BASE_UTF8_H
|
||||
#define ANDROID_BASE_UTF8_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <string>
|
||||
#else
|
||||
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
|
||||
#include <fcntl.h> // open
|
||||
#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);
|
||||
#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
|
||||
int open(const char* name, int flags, ...);
|
||||
int unlink(const char* name);
|
||||
#else
|
||||
using ::open;
|
||||
using ::unlink;
|
||||
#endif
|
||||
|
||||
} // namespace utf8
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_BASE_UTF8_H
|
||||
428
app/src/main/jni/crash_dump/libbase/logging.cpp
Normal file
428
app/src/main/jni/crash_dump/libbase/logging.cpp
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "android-base/logging.h"
|
||||
|
||||
#include <libgen.h>
|
||||
|
||||
// For getprogname(3) or program_invocation_short_name.
|
||||
#if defined(__ANDROID__) || defined(__APPLE__)
|
||||
#include <stdlib.h>
|
||||
#elif defined(__GLIBC__)
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include "android-base/macros.h"
|
||||
#include "android-base/strings.h"
|
||||
#include "cutils/threads.h"
|
||||
|
||||
// Headers for LogMessage::LogLine.
|
||||
#ifdef __ANDROID__
|
||||
#include <android/set_abort_message.h>
|
||||
#include "cutils/log.h"
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// For gettid.
|
||||
#if defined(__APPLE__)
|
||||
#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef uint32_t thread_id;
|
||||
#else
|
||||
typedef pid_t thread_id;
|
||||
#endif
|
||||
|
||||
static thread_id GetThreadId() {
|
||||
#if defined(__BIONIC__)
|
||||
return gettid();
|
||||
#elif defined(__APPLE__)
|
||||
return syscall(SYS_thread_selfid);
|
||||
#elif defined(__linux__)
|
||||
return syscall(__NR_gettid);
|
||||
#elif defined(_WIN32)
|
||||
return GetCurrentThreadId();
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
#ifndef _WIN32
|
||||
using std::mutex;
|
||||
using std::lock_guard;
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
const char* getprogname() {
|
||||
return program_invocation_short_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
const char* getprogname() {
|
||||
static bool first = true;
|
||||
static char progname[MAX_PATH] = {};
|
||||
|
||||
if (first) {
|
||||
CHAR longname[MAX_PATH];
|
||||
DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
|
||||
if ((nchars >= arraysize(longname)) || (nchars == 0)) {
|
||||
// String truncation or some other error.
|
||||
strcpy(progname, "<unknown>");
|
||||
} else {
|
||||
strcpy(progname, basename(longname));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
return progname;
|
||||
}
|
||||
|
||||
class mutex {
|
||||
public:
|
||||
mutex() {
|
||||
InitializeCriticalSection(&critical_section_);
|
||||
}
|
||||
~mutex() {
|
||||
DeleteCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION critical_section_;
|
||||
};
|
||||
|
||||
template <typename LockT>
|
||||
class lock_guard {
|
||||
public:
|
||||
explicit lock_guard(LockT& lock) : lock_(lock) {
|
||||
lock_.lock();
|
||||
}
|
||||
|
||||
~lock_guard() {
|
||||
lock_.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
LockT& lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(lock_guard);
|
||||
};
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace android {
|
||||
namespace base {
|
||||
|
||||
static auto& logging_lock = *new mutex();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static auto& gLogger = *new LogFunction(LogdLogger());
|
||||
#else
|
||||
static auto& gLogger = *new LogFunction(StderrLogger);
|
||||
#endif
|
||||
|
||||
static bool gInitialized = false;
|
||||
static LogSeverity gMinimumLogSeverity = INFO;
|
||||
static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
|
||||
|
||||
LogSeverity GetMinimumLogSeverity() {
|
||||
return gMinimumLogSeverity;
|
||||
}
|
||||
|
||||
static const char* ProgramInvocationName() {
|
||||
if (gProgramInvocationName == nullptr) {
|
||||
gProgramInvocationName.reset(new std::string(getprogname()));
|
||||
}
|
||||
|
||||
return gProgramInvocationName->c_str();
|
||||
}
|
||||
|
||||
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
|
||||
unsigned int line, const char* message) {
|
||||
static const char log_characters[] = "VDIWEF";
|
||||
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
|
||||
"Mismatch in size of log_characters and values in LogSeverity");
|
||||
char severity_char = log_characters[severity];
|
||||
fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
|
||||
severity_char, getpid(), GetThreadId(), file, line, message);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
|
||||
}
|
||||
|
||||
static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
|
||||
ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
|
||||
ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
|
||||
};
|
||||
static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
|
||||
"Mismatch in size of kLogSeverityToAndroidLogPriority and values "
|
||||
"in LogSeverity");
|
||||
|
||||
static const log_id kLogIdToAndroidLogId[] = {
|
||||
LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
|
||||
};
|
||||
static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
|
||||
"Mismatch in size of kLogIdToAndroidLogId and values in LogId");
|
||||
|
||||
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
|
||||
const char* file, unsigned int line,
|
||||
const char* message) {
|
||||
int priority = kLogSeverityToAndroidLogPriority[severity];
|
||||
if (id == DEFAULT) {
|
||||
id = default_log_id_;
|
||||
}
|
||||
|
||||
log_id lg_id = kLogIdToAndroidLogId[id];
|
||||
|
||||
if (priority == ANDROID_LOG_FATAL) {
|
||||
__android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
|
||||
message);
|
||||
} else {
|
||||
__android_log_buf_print(lg_id, priority, tag, "%s", message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void InitLogging(char* argv[], LogFunction&& logger) {
|
||||
SetLogger(std::forward<LogFunction>(logger));
|
||||
InitLogging(argv);
|
||||
}
|
||||
|
||||
void InitLogging(char* argv[]) {
|
||||
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) {
|
||||
gProgramInvocationName.reset(new std::string(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':
|
||||
gMinimumLogSeverity = VERBOSE;
|
||||
continue;
|
||||
case 'd':
|
||||
gMinimumLogSeverity = DEBUG;
|
||||
continue;
|
||||
case 'i':
|
||||
gMinimumLogSeverity = INFO;
|
||||
continue;
|
||||
case 'w':
|
||||
gMinimumLogSeverity = WARNING;
|
||||
continue;
|
||||
case 'e':
|
||||
gMinimumLogSeverity = ERROR;
|
||||
continue;
|
||||
case 'f':
|
||||
gMinimumLogSeverity = FATAL;
|
||||
continue;
|
||||
// liblog will even suppress FATAL if you say 's' for silent, but that's
|
||||
// crazy!
|
||||
case 's':
|
||||
gMinimumLogSeverity = FATAL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
|
||||
<< ")";
|
||||
}
|
||||
}
|
||||
|
||||
void SetLogger(LogFunction&& logger) {
|
||||
lock_guard<mutex> lock(logging_lock);
|
||||
gLogger = std::move(logger);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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, LogId id,
|
||||
LogSeverity severity, int error)
|
||||
: file_(GetFileBasename(file)),
|
||||
line_number_(line),
|
||||
id_(id),
|
||||
severity_(severity),
|
||||
error_(error) {
|
||||
}
|
||||
|
||||
const char* GetFile() const {
|
||||
return file_;
|
||||
}
|
||||
|
||||
unsigned int GetLineNumber() const {
|
||||
return line_number_;
|
||||
}
|
||||
|
||||
LogSeverity GetSeverity() const {
|
||||
return severity_;
|
||||
}
|
||||
|
||||
LogId GetId() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
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 LogId id_;
|
||||
const LogSeverity severity_;
|
||||
const int error_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LogMessageData);
|
||||
};
|
||||
|
||||
LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
|
||||
LogSeverity severity, int error)
|
||||
: data_(new LogMessageData(file, line, id, severity, error)) {
|
||||
}
|
||||
|
||||
LogMessage::~LogMessage() {
|
||||
// Finish constructing the message.
|
||||
if (data_->GetError() != -1) {
|
||||
data_->GetBuffer() << ": " << strerror(data_->GetError());
|
||||
}
|
||||
std::string msg(data_->ToString());
|
||||
|
||||
{
|
||||
// Do the actual logging with the lock held.
|
||||
lock_guard<mutex> lock(logging_lock);
|
||||
if (msg.find('\n') == std::string::npos) {
|
||||
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
|
||||
data_->GetSeverity(), msg.c_str());
|
||||
} else {
|
||||
msg += '\n';
|
||||
size_t i = 0;
|
||||
while (i < msg.size()) {
|
||||
size_t nl = msg.find('\n', i);
|
||||
msg[nl] = '\0';
|
||||
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
|
||||
data_->GetSeverity(), &msg[i]);
|
||||
i = nl + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Abort if necessary.
|
||||
if (data_->GetSeverity() == FATAL) {
|
||||
#ifdef __ANDROID__
|
||||
android_set_abort_message(msg.c_str());
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& LogMessage::stream() {
|
||||
return data_->GetBuffer();
|
||||
}
|
||||
|
||||
void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
|
||||
LogSeverity severity, const char* message) {
|
||||
const char* tag = ProgramInvocationName();
|
||||
gLogger(id, severity, tag, file, line, message);
|
||||
}
|
||||
|
||||
ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
|
||||
old_ = gMinimumLogSeverity;
|
||||
gMinimumLogSeverity = level;
|
||||
}
|
||||
|
||||
ScopedLogSeverity::~ScopedLogSeverity() {
|
||||
gMinimumLogSeverity = old_;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
281
app/src/main/jni/crash_dump/libbase/logging_test.cpp
Normal file
281
app/src/main/jni/crash_dump/libbase/logging_test.cpp
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* 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 "android-base/file.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
|
||||
|
||||
class CapturedStderr {
|
||||
public:
|
||||
CapturedStderr() : old_stderr_(-1) {
|
||||
init();
|
||||
}
|
||||
|
||||
~CapturedStderr() {
|
||||
reset();
|
||||
}
|
||||
|
||||
int fd() const {
|
||||
return temp_file_.fd;
|
||||
}
|
||||
|
||||
private:
|
||||
void init() {
|
||||
#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.
|
||||
ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
|
||||
#endif
|
||||
old_stderr_ = dup(STDERR_FILENO);
|
||||
ASSERT_NE(-1, old_stderr_);
|
||||
ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
|
||||
ASSERT_EQ(0, close(old_stderr_));
|
||||
// Note: cannot restore prior setvbuf() setting.
|
||||
}
|
||||
|
||||
TemporaryFile temp_file_;
|
||||
int old_stderr_;
|
||||
};
|
||||
|
||||
#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";
|
||||
}
|
||||
|
||||
std::string make_log_pattern(android::base::LogSeverity severity,
|
||||
const char* message) {
|
||||
static const char* log_characters = "VDIWEF";
|
||||
char log_char = log_characters[severity];
|
||||
std::string holder(__FILE__);
|
||||
return android::base::StringPrintf(
|
||||
"%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s",
|
||||
log_char, basename(&holder[0]), message);
|
||||
}
|
||||
|
||||
TEST(logging, LOG) {
|
||||
ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
|
||||
|
||||
// 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.
|
||||
{
|
||||
CapturedStderr cap;
|
||||
LOG(WARNING) << "foobar";
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_GT(output.length(), strlen("foobar"));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::regex message_regex(
|
||||
make_log_pattern(android::base::WARNING, "foobar"));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
CapturedStderr cap;
|
||||
LOG(INFO) << "foobar";
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_GT(output.length(), strlen("foobar"));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::regex message_regex(
|
||||
make_log_pattern(android::base::INFO, "foobar"));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
CapturedStderr cap;
|
||||
LOG(DEBUG) << "foobar";
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_TRUE(output.empty());
|
||||
}
|
||||
|
||||
{
|
||||
android::base::ScopedLogSeverity severity(android::base::DEBUG);
|
||||
CapturedStderr cap;
|
||||
LOG(DEBUG) << "foobar";
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_GT(output.length(), strlen("foobar"));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::regex message_regex(
|
||||
make_log_pattern(android::base::DEBUG, "foobar"));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test whether LOG() saves and restores errno.
|
||||
{
|
||||
CapturedStderr cap;
|
||||
errno = 12345;
|
||||
LOG(INFO) << (errno = 67890);
|
||||
EXPECT_EQ(12345, errno) << "errno was not restored";
|
||||
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
EXPECT_NE(nullptr, strstr(output.c_str(), "67890")) << output;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::regex message_regex(
|
||||
make_log_pattern(android::base::INFO, "67890"));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test whether LOG() has a dangling if with no else.
|
||||
{
|
||||
CapturedStderr cap;
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(logging, PLOG) {
|
||||
{
|
||||
CapturedStderr cap;
|
||||
errno = ENOENT;
|
||||
PLOG(INFO) << "foobar";
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_GT(output.length(), strlen("foobar"));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::regex message_regex(make_log_pattern(
|
||||
android::base::INFO, "foobar: No such file or directory"));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST(logging, UNIMPLEMENTED) {
|
||||
{
|
||||
CapturedStderr cap;
|
||||
errno = ENOENT;
|
||||
UNIMPLEMENTED(ERROR);
|
||||
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
|
||||
|
||||
std::string output;
|
||||
android::base::ReadFdToString(cap.fd(), &output);
|
||||
ASSERT_GT(output.length(), strlen("unimplemented"));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
std::string expected_message =
|
||||
android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
|
||||
std::regex message_regex(
|
||||
make_log_pattern(android::base::ERROR, expected_message.c_str()));
|
||||
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
78
app/src/main/jni/crash_dump/libbase/parseint_test.cpp
Normal file
78
app/src/main/jni/crash_dump/libbase/parseint_test.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
|
||||
TEST(parseint, signed_smoke) {
|
||||
int i;
|
||||
ASSERT_FALSE(android::base::ParseInt("x", &i));
|
||||
ASSERT_FALSE(android::base::ParseInt("123x", &i));
|
||||
|
||||
ASSERT_TRUE(android::base::ParseInt("123", &i));
|
||||
ASSERT_EQ(123, i);
|
||||
ASSERT_TRUE(android::base::ParseInt("-123", &i));
|
||||
ASSERT_EQ(-123, i);
|
||||
|
||||
short s;
|
||||
ASSERT_TRUE(android::base::ParseInt("1234", &s));
|
||||
ASSERT_EQ(1234, s);
|
||||
|
||||
ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15));
|
||||
ASSERT_EQ(12, i);
|
||||
ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
|
||||
ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
|
||||
}
|
||||
|
||||
TEST(parseint, unsigned_smoke) {
|
||||
unsigned int i;
|
||||
ASSERT_FALSE(android::base::ParseUint("x", &i));
|
||||
ASSERT_FALSE(android::base::ParseUint("123x", &i));
|
||||
|
||||
ASSERT_TRUE(android::base::ParseUint("123", &i));
|
||||
ASSERT_EQ(123u, i);
|
||||
ASSERT_FALSE(android::base::ParseUint("-123", &i));
|
||||
|
||||
unsigned short s;
|
||||
ASSERT_TRUE(android::base::ParseUint("1234", &s));
|
||||
ASSERT_EQ(1234u, s);
|
||||
|
||||
ASSERT_TRUE(android::base::ParseUint("12", &i, 15u));
|
||||
ASSERT_EQ(12u, i);
|
||||
ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
|
||||
ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
|
||||
}
|
||||
|
||||
TEST(parseint, no_implicit_octal) {
|
||||
int i;
|
||||
ASSERT_TRUE(android::base::ParseInt("0123", &i));
|
||||
ASSERT_EQ(123, i);
|
||||
|
||||
unsigned int u;
|
||||
ASSERT_TRUE(android::base::ParseUint("0123", &u));
|
||||
ASSERT_EQ(123u, u);
|
||||
}
|
||||
|
||||
TEST(parseint, explicit_hex) {
|
||||
int i;
|
||||
ASSERT_TRUE(android::base::ParseInt("0x123", &i));
|
||||
ASSERT_EQ(0x123, i);
|
||||
|
||||
unsigned int u;
|
||||
ASSERT_TRUE(android::base::ParseUint("0x123", &u));
|
||||
ASSERT_EQ(0x123u, u);
|
||||
}
|
||||
82
app/src/main/jni/crash_dump/libbase/parsenetaddress.cpp
Normal file
82
app/src/main/jni/crash_dump/libbase/parsenetaddress.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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
|
||||
127
app/src/main/jni/crash_dump/libbase/parsenetaddress_test.cpp
Normal file
127
app/src/main/jni/crash_dump/libbase/parsenetaddress_test.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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));
|
||||
}
|
||||
85
app/src/main/jni/crash_dump/libbase/stringprintf.cpp
Normal file
85
app/src/main/jni/crash_dump/libbase/stringprintf.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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];
|
||||
|
||||
// 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
|
||||
60
app/src/main/jni/crash_dump/libbase/stringprintf_test.cpp
Normal file
60
app/src/main/jni/crash_dump/libbase/stringprintf_test.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
104
app/src/main/jni/crash_dump/libbase/strings.cpp
Normal file
104
app/src/main/jni/crash_dump/libbase/strings.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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;
|
||||
do {
|
||||
found = s.find_first_of(delimiters, base);
|
||||
result.push_back(s.substr(base, found - base));
|
||||
base = found + 1;
|
||||
} while (found != s.npos);
|
||||
|
||||
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(const std::string& s, const char* prefix) {
|
||||
return s.compare(0, strlen(prefix), prefix) == 0;
|
||||
}
|
||||
|
||||
bool EndsWith(const std::string& s, const char* suffix) {
|
||||
size_t suffix_length = strlen(suffix);
|
||||
size_t string_length = s.size();
|
||||
if (suffix_length > string_length) {
|
||||
return false;
|
||||
}
|
||||
size_t offset = string_length - suffix_length;
|
||||
return s.compare(offset, suffix_length, suffix) == 0;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
177
app/src/main/jni/crash_dump/libbase/strings_test.cpp
Normal file
177
app/src/main/jni/crash_dump/libbase/strings_test.cpp
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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_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, 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, startswith_prefix_too_long) {
|
||||
ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
|
||||
}
|
||||
|
||||
TEST(strings, startswith_contains_prefix) {
|
||||
ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
|
||||
ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
|
||||
}
|
||||
|
||||
TEST(strings, endswith_empty) {
|
||||
ASSERT_FALSE(android::base::EndsWith("", "foo"));
|
||||
ASSERT_TRUE(android::base::EndsWith("", ""));
|
||||
}
|
||||
|
||||
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, endswith_prefix_too_long) {
|
||||
ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
|
||||
}
|
||||
|
||||
TEST(strings, endswith_contains_prefix) {
|
||||
ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
|
||||
ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
|
||||
}
|
||||
25
app/src/main/jni/crash_dump/libbase/test_main.cpp
Normal file
25
app/src/main/jni/crash_dump/libbase/test_main.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
102
app/src/main/jni/crash_dump/libbase/test_utils.cpp
Normal file
102
app/src/main/jni/crash_dump/libbase/test_utils.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 "android-base/test_utils.h"
|
||||
#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
int mkstemp(char* template_name) {
|
||||
if (_mktemp(template_name) == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
// Use open() to match the close() that TemporaryFile's destructor does.
|
||||
// Use O_BINARY to match base file APIs.
|
||||
return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
|
||||
S_IRUSR | S_IWUSR);
|
||||
}
|
||||
|
||||
char* mkdtemp(char* template_name) {
|
||||
if (_mktemp(template_name) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (_mkdir(template_name) == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
return template_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string GetSystemTempDir() {
|
||||
#if defined(__ANDROID__)
|
||||
return "/data/local/tmp";
|
||||
#elif defined(_WIN32)
|
||||
char tmp_dir[MAX_PATH];
|
||||
DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
|
||||
CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
|
||||
CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
|
||||
|
||||
// GetTempPath() returns a path with a trailing slash, but init()
|
||||
// does not expect that, so remove it.
|
||||
CHECK_EQ(tmp_dir[result - 1], '\\');
|
||||
tmp_dir[result - 1] = '\0';
|
||||
return tmp_dir;
|
||||
#else
|
||||
return "/tmp";
|
||||
#endif
|
||||
}
|
||||
|
||||
TemporaryFile::TemporaryFile() {
|
||||
init(GetSystemTempDir());
|
||||
}
|
||||
|
||||
TemporaryFile::~TemporaryFile() {
|
||||
close(fd);
|
||||
unlink(path);
|
||||
}
|
||||
|
||||
void TemporaryFile::init(const std::string& tmp_dir) {
|
||||
snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
|
||||
OS_PATH_SEPARATOR);
|
||||
fd = mkstemp(path);
|
||||
}
|
||||
|
||||
TemporaryDir::TemporaryDir() {
|
||||
init(GetSystemTempDir());
|
||||
}
|
||||
|
||||
TemporaryDir::~TemporaryDir() {
|
||||
rmdir(path);
|
||||
}
|
||||
|
||||
bool TemporaryDir::init(const std::string& tmp_dir) {
|
||||
snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
|
||||
OS_PATH_SEPARATOR);
|
||||
return (mkdtemp(path) != nullptr);
|
||||
}
|
||||
187
app/src/main/jni/crash_dump/libbase/utf8.cpp
Normal file
187
app/src/main/jni/crash_dump/libbase/utf8.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* 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 <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);
|
||||
}
|
||||
|
||||
// Versions of standard library APIs that support UTF-8 strings.
|
||||
namespace utf8 {
|
||||
|
||||
int open(const char* name, int flags, ...) {
|
||||
std::wstring name_utf16;
|
||||
if (!UTF8ToWide(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 (!UTF8ToWide(name, &name_utf16)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wunlink(name_utf16.c_str());
|
||||
}
|
||||
|
||||
} // namespace utf8
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
412
app/src/main/jni/crash_dump/libbase/utf8_test.cpp
Normal file
412
app/src/main/jni/crash_dump/libbase/utf8_test.cpp
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* 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 "android-base/macros.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));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace android
|
||||
Loading…
Add table
Add a link
Reference in a new issue