android_system_core/debuggerd/test/tombstone_test.cpp
Christopher Ferris 99235e9967 Fix problem with wait_for_gdb.
When someone enables wait_for_gdb, activity manager will kill the
stopped process before a developer can attach to the process. To
allow debugging in this case, change the code to only contact the
activity manager right before continuing the process that is
crashing.

Also, modify the conditions under which to do a gdb attach. The previous
code did a partial attach if perform_dump failed. The new version simply
allows an attach regardless of whether perform_dump passes or fails.

Bug: 28409358
(cherry picked from commit 9818bd2bbe)

Change-Id: I42f464b69332748e16b07d9d00f44b3aa26ce8b7
2016-05-05 10:50:39 -07:00

633 lines
20 KiB
C++

/*
* 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 <stdlib.h>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include <android-base/file.h>
#include "utility.h"
#include "BacktraceMock.h"
#include "elf_fake.h"
#include "host_signal_fixup.h"
#include "log_fake.h"
#include "ptrace_fake.h"
// In order to test this code, we need to include the tombstone.cpp code.
// Including it, also allows us to override the ptrace function.
#define ptrace ptrace_fake
#include "tombstone.cpp"
void dump_registers(log_t*, pid_t) {
}
void dump_memory_and_code(log_t*, Backtrace*) {
}
void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
}
class TombstoneTest : public ::testing::Test {
protected:
virtual void SetUp() {
map_mock_.reset(new BacktraceMapMock());
backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, data_template, sizeof(data_template));
int tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, tmp_template, sizeof(tmp_template));
tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
abort();
}
}
if (unlink(tmp_file) == -1) {
abort();
}
log_.tfd = tombstone_fd;
amfd_data_.clear();
log_.amfd_data = &amfd_data_;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
resetLogs();
elf_set_fake_build_id("");
siginfo_t si;
si.si_signo = SIGABRT;
ptrace_set_fake_getsiginfo(si);
}
virtual void TearDown() {
if (log_.tfd >= 0) {
close(log_.tfd);
}
}
std::unique_ptr<BacktraceMapMock> map_mock_;
std::unique_ptr<BacktraceMock> backtrace_mock_;
log_t log_;
std::string amfd_data_;
};
TEST_F(TombstoneTest, single_map) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map_mock_->AddMap(map);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
#else
" 01234000-01234fff --- 0 1000\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, single_map_elf_build_id) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map.flags = PROT_READ;
map.name = "/system/lib/libfake.so";
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
#else
" 01234000-01234fff r-- 0 1000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
// Even though build id is present, it should not be printed in either of
// these cases.
TEST_F(TombstoneTest, single_map_no_build_id) {
backtrace_map_t map;
#if defined(__LP64__)
map.start = 0x123456789abcd000UL;
map.end = 0x123456789abdf000UL;
#else
map.start = 0x1234000;
map.end = 0x1235000;
#endif
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.name = "/system/lib/libfake.so";
map_mock_->AddMap(map);
elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n"
" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n";
#else
" 01234000-01234fff -w- 0 1000\n"
" 01234000-01234fff -w- 0 1000 /system/lib/libfake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps) {
backtrace_map_t map;
map.start = 0xa234000;
map.end = 0xa235000;
map_mock_->AddMap(map);
map.start = 0xa334000;
map.end = 0xa335000;
map.offset = 0xf000;
map.flags = PROT_READ;
map_mock_->AddMap(map);
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
" 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a234000-0a234fff --- 0 1000\n"
" 0a334000-0a334fff r-- f000 1000\n"
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
"--->Fault address falls at 00001000 before any mapped regions\n"
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0xa533000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->Fault address falls at 0a533000 between mapped regions\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
si.si_addr = reinterpret_cast<void*>(0xa534040);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
"--->0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
map.load_base = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
map.load_base = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = SIGBUS;
#if defined(__LP64__)
si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
#else
si.si_addr = reinterpret_cast<void*>(0xf534040UL);
#endif
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
"--->Fault address falls at 0f534040 after any mapped regions\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
map.load_base = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
siginfo_t si;
si.si_signo = 0;
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n";
#else
" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
}
TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) {
backtrace_map_t map;
map.start = 0xa434000;
map.end = 0xa435000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
for (int i = 1; i < 255; i++) {
ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
siginfo_t si;
si.si_signo = i;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
bool has_addr = false;
switch (si.si_signo) {
case SIGBUS:
case SIGFPE:
case SIGILL:
case SIGSEGV:
case SIGTRAP:
has_addr = true;
break;
}
const char* expected_addr_dump = \
"\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
#else
"--->Fault address falls at 00001000 before any mapped regions\n"
" 0a434000-0a434fff -w- 0 1000\n";
#endif
const char* expected_dump = \
"\nmemory map:\n"
#if defined(__LP64__)
" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
#else
" 0a434000-0a434fff -w- 0 1000\n";
#endif
if (has_addr) {
ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
<< "Signal " << si.si_signo << " expected to include an address.";
} else {
ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
<< "Signal " << si.si_signo << " is not expected to include an address.";
}
ASSERT_STREQ("", amfd_data_.c_str());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
}
TEST_F(TombstoneTest, dump_signal_info_error) {
siginfo_t si;
si.si_signo = 0;
ptrace_set_fake_getsiginfo(si);
dump_signal_info(&log_, 123, SIGSEGV, 10);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ("", tombstone_contents.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
ASSERT_STREQ("", amfd_data_.c_str());
}
TEST_F(TombstoneTest, dump_log_file_error) {
log_.should_retrieve_logcat = true;
dump_log_file(&log_, 123, "/fake/filename", 10);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ("", tombstone_contents.c_str());
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
getFakeLogPrint().c_str());
ASSERT_STREQ("", amfd_data_.c_str());
}
TEST_F(TombstoneTest, dump_header_info) {
dump_header_info(&log_);
std::string expected = "Build fingerprint: 'unknown'\nRevision: 'unknown'\n";
expected += android::base::StringPrintf("ABI: '%s'\n", ABI_STRING);
ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}