Merge "ueventd: fixup ueventd_test.cpp"
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index cb02a6f..92d1752 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -26,8 +26,8 @@
}
#include <android-base/memory.h>
-#include <UniquePtr.h>
#include <gatekeeper/gatekeeper.h>
+#include <nativehelper/UniquePtr.h>
#include <iostream>
#include <unordered_map>
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
index 3463c29..229f9a9 100644
--- a/gatekeeperd/SoftGateKeeperDevice.h
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -19,7 +19,7 @@
#include "SoftGateKeeper.h"
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
using namespace gatekeeper;
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index 47a8bfa..b3aea7b 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -19,7 +19,7 @@
#include <gtest/gtest.h>
#include <hardware/hw_auth_token.h>
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
#include "../SoftGateKeeper.h"
diff --git a/init/README.md b/init/README.md
index 422fdad..f3b57bc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,18 @@
> Sets the child's /proc/self/oom\_score\_adj to the specified value,
which must range from -1000 to 1000.
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
`shutdown <shutdown_behavior>`
> Set shutdown behavior of the service process. When this is not specified,
the service is killed during shutdown process by using SIGTERM and SIGKILL.
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 8196d58..30a845c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -323,11 +323,11 @@
UmountStat stat = UmountPartitions(timeout - t.duration());
if (stat != UMOUNT_STAT_SUCCESS) {
LOG(INFO) << "umount timeout, last resort, kill all and try";
- if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
+ if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
KillAllProcesses();
// even if it succeeds, still it is timeout and do not run fsck with all processes killed
- UmountPartitions(0ms);
- if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
+ UmountStat st = UmountPartitions(0ms);
+ if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
}
if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
diff --git a/init/service.cpp b/init/service.cpp
index 7a657c8..82dd9b1 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -171,6 +171,9 @@
ioprio_pri_(0),
priority_(0),
oom_score_adjust_(-1000),
+ swappiness_(-1),
+ soft_limit_in_bytes_(-1),
+ limit_in_bytes_(-1),
args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -196,6 +199,9 @@
ioprio_pri_(0),
priority_(0),
oom_score_adjust_(-1000),
+ swappiness_(-1),
+ soft_limit_in_bytes_(-1),
+ limit_in_bytes_(-1),
args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -491,6 +497,30 @@
return true;
}
+bool Service::ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &swappiness_, 0)) {
+ *err = "swappiness value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
+bool Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &limit_in_bytes_, 0)) {
+ *err = "limit_in_bytes value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
+bool Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) {
+ *err = "soft_limit_in_bytes value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
seclabel_ = args[1];
return true;
@@ -609,6 +639,12 @@
{"onrestart", {1, kMax, &Service::ParseOnrestart}},
{"oom_score_adjust",
{1, 1, &Service::ParseOomScoreAdjust}},
+ {"memcg.swappiness",
+ {1, 1, &Service::ParseMemcgSwappiness}},
+ {"memcg.soft_limit_in_bytes",
+ {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
+ {"memcg.limit_in_bytes",
+ {1, 1, &Service::ParseMemcgLimitInBytes}},
{"namespace", {1, 2, &Service::ParseNamespace}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
@@ -795,6 +831,24 @@
if (errno != 0) {
PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
<< name_ << "'";
+ } else {
+ if (swappiness_ != -1) {
+ if (!setProcessGroupSwappiness(uid_, pid_, swappiness_)) {
+ PLOG(ERROR) << "setProcessGroupSwappiness failed";
+ }
+ }
+
+ if (soft_limit_in_bytes_ != -1) {
+ if (!setProcessGroupSoftLimit(uid_, pid_, soft_limit_in_bytes_)) {
+ PLOG(ERROR) << "setProcessGroupSoftLimit failed";
+ }
+ }
+
+ if (limit_in_bytes_ != -1) {
+ if (!setProcessGroupLimit(uid_, pid_, limit_in_bytes_)) {
+ PLOG(ERROR) << "setProcessGroupLimit failed";
+ }
+ }
}
if ((flags_ & SVC_EXEC) != 0) {
diff --git a/init/service.h b/init/service.h
index f682abd..62a3299 100644
--- a/init/service.h
+++ b/init/service.h
@@ -134,6 +134,9 @@
bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err);
bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
@@ -181,6 +184,10 @@
int oom_score_adjust_;
+ int swappiness_;
+ int soft_limit_in_bytes_;
+ int limit_in_bytes_;
+
bool process_cgroup_empty_ = false;
std::vector<std::string> args_;
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 36a2e44..7ccd7db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -15,7 +15,7 @@
*/
#include "nativeloader/native_loader.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/ScopedUtfChars.h>
#include <dlfcn.h>
#ifdef __ANDROID__
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index f0c3795..9fa4154 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -33,6 +33,10 @@
int createProcessGroup(uid_t uid, int initialPid);
+bool setProcessGroupSwappiness(uid_t uid, int initialPid, int swappiness);
+bool setProcessGroupSoftLimit(uid_t uid, int initialPid, int64_t softLimitInBytes);
+bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
+
void removeAllProcessGroups(void);
__END_DECLS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9b8248e..8526b3a 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -35,12 +35,15 @@
#include <set>
#include <thread>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
+using android::base::WriteStringToFile;
+
using namespace std::chrono_literals;
#define MEM_CGROUP_PATH "/dev/memcg/apps"
@@ -402,22 +405,40 @@
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
- int fd = open(path, O_WRONLY);
- if (fd == -1) {
- int ret = -errno;
- PLOG(ERROR) << "Failed to open " << path;
- return ret;
- }
-
- char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
- int len = snprintf(pid, sizeof(pid), "%d", initialPid);
-
int ret = 0;
- if (write(fd, pid, len) < 0) {
+ if (!WriteStringToFile(std::to_string(initialPid), path)) {
ret = -errno;
- PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
+ PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << path;
}
- close(fd);
return ret;
}
+
+static bool setProcessGroupValue(uid_t uid, int pid, const char* fileName, int64_t value) {
+ char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+ if (strcmp(getCgroupRootPath(), MEM_CGROUP_PATH)) {
+ PLOG(ERROR) << "Memcg is not mounted." << path;
+ return false;
+ }
+
+ convertUidPidToPath(path, sizeof(path), uid, pid);
+ strlcat(path, fileName, sizeof(path));
+
+ if (!WriteStringToFile(std::to_string(value), path)) {
+ PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
+ return false;
+ }
+ return true;
+}
+
+bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) {
+ return setProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
+}
+
+bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) {
+ return setProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
+}
+
+bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) {
+ return setProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
+}
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index a800c31..e962a73 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -96,7 +96,8 @@
}
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
- return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
+ return valid_ && (regs->StepIfSignalHandler(process_memory) ||
+ interface_->Step(rel_pc, regs, process_memory) ||
(gnu_debugdata_interface_ &&
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
}
@@ -147,21 +148,22 @@
machine_type_ = e_machine;
if (e_machine == EM_ARM) {
interface.reset(new ElfInterfaceArm(memory));
- } else {
+ } else if (e_machine == EM_386) {
interface.reset(new ElfInterface32(memory));
+ } else {
+ ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
+ return nullptr;
}
} else if (class_type_ == ELFCLASS64) {
Elf64_Half e_machine;
if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
return nullptr;
}
-
if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
// Unsupported.
ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
return nullptr;
}
-
machine_type_ = e_machine;
interface.reset(new ElfInterface64(memory));
}
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index aa59e31..33319b1 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -258,49 +258,51 @@
return regs;
}
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+ // Put the registers in the expected order.
+ regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+ regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+ regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+ regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+ regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+ regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+ regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+ regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+ regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+ SetFromRaw();
+}
+
static Regs* CreateFromX86Ucontext(void* ucontext) {
x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
RegsX86* regs = new RegsX86();
- // Put the registers in the expected order.
- (*regs)[X86_REG_GS] = x86_ucontext->uc_mcontext.gs;
- (*regs)[X86_REG_FS] = x86_ucontext->uc_mcontext.fs;
- (*regs)[X86_REG_ES] = x86_ucontext->uc_mcontext.es;
- (*regs)[X86_REG_DS] = x86_ucontext->uc_mcontext.ds;
- (*regs)[X86_REG_EDI] = x86_ucontext->uc_mcontext.edi;
- (*regs)[X86_REG_ESI] = x86_ucontext->uc_mcontext.esi;
- (*regs)[X86_REG_EBP] = x86_ucontext->uc_mcontext.ebp;
- (*regs)[X86_REG_ESP] = x86_ucontext->uc_mcontext.esp;
- (*regs)[X86_REG_EBX] = x86_ucontext->uc_mcontext.ebx;
- (*regs)[X86_REG_EDX] = x86_ucontext->uc_mcontext.edx;
- (*regs)[X86_REG_ECX] = x86_ucontext->uc_mcontext.ecx;
- (*regs)[X86_REG_EAX] = x86_ucontext->uc_mcontext.eax;
- (*regs)[X86_REG_EIP] = x86_ucontext->uc_mcontext.eip;
- regs->SetFromRaw();
+ regs->SetFromUcontext(x86_ucontext);
return regs;
}
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+ // R8-R15
+ memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+ // Rest of the registers.
+ regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+ regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+ regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+ regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+ regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+ regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+ regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+ regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+ regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+ SetFromRaw();
+}
+
static Regs* CreateFromX86_64Ucontext(void* ucontext) {
x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
RegsX86_64* regs = new RegsX86_64();
- // Put the registers in the expected order.
-
- // R8-R15
- memcpy(&(*regs)[X86_64_REG_R8], &x86_64_ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
- // Rest of the registers.
- (*regs)[X86_64_REG_RDI] = x86_64_ucontext->uc_mcontext.rdi;
- (*regs)[X86_64_REG_RSI] = x86_64_ucontext->uc_mcontext.rsi;
- (*regs)[X86_64_REG_RBP] = x86_64_ucontext->uc_mcontext.rbp;
- (*regs)[X86_64_REG_RBX] = x86_64_ucontext->uc_mcontext.rbx;
- (*regs)[X86_64_REG_RDX] = x86_64_ucontext->uc_mcontext.rdx;
- (*regs)[X86_64_REG_RAX] = x86_64_ucontext->uc_mcontext.rax;
- (*regs)[X86_64_REG_RCX] = x86_64_ucontext->uc_mcontext.rcx;
- (*regs)[X86_64_REG_RSP] = x86_64_ucontext->uc_mcontext.rsp;
- (*regs)[X86_64_REG_RIP] = x86_64_ucontext->uc_mcontext.rip;
-
- regs->SetFromRaw();
+ regs->SetFromUcontext(x86_64_ucontext);
return regs;
}
@@ -348,4 +350,178 @@
return regs;
}
+bool RegsArm::StepIfSignalHandler(Memory* memory) {
+ uint32_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ uint64_t offset = 0;
+ if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+ // non-RT sigreturn call.
+ // __restore:
+ //
+ // Form 1 (arm):
+ // 0x77 0x70 mov r7, #0x77
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0x77 0x00 0x90 0xef svc 0x00900077
+ //
+ // Form 3 (thumb):
+ // 0x77 0x27 movs r7, #77
+ // 0x00 0xdf svc 0
+ if (!memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == 0x5ac3c35a) {
+ // SP + uc_mcontext offset + r0 offset.
+ offset = sp() + 0x14 + 0xc;
+ } else {
+ // SP + r0 offset
+ offset = sp() + 0xc;
+ }
+ } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+ // RT sigreturn call.
+ // __restore_rt:
+ //
+ // Form 1 (arm):
+ // 0xad 0x70 mov r7, #0xad
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0xad 0x00 0x90 0xef svc 0x009000ad
+ //
+ // Form 3 (thumb):
+ // 0xad 0x27 movs r7, #ad
+ // 0x00 0xdf svc 0
+ if (!memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == sp() + 8) {
+ // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+ } else {
+ // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 0x80 + 0x14 + 0xc;
+ }
+ }
+ if (offset == 0) {
+ return false;
+ }
+
+ if (!memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+ return false;
+ }
+ SetFromRaw();
+ return true;
+}
+
+bool RegsArm64::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ // Look for the kernel sigreturn function.
+ // __kernel_rt_sigreturn:
+ // 0xd2801168 mov x8, #0x8b
+ // 0xd4000001 svc #0x0
+ if (data != 0xd4000001d2801168ULL) {
+ return false;
+ }
+
+ // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+ if (!memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(), sizeof(uint64_t) * ARM64_REG_LAST)) {
+ return false;
+ }
+
+ SetFromRaw();
+ return true;
+}
+
+bool RegsX86::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ if (data == 0x80cd00000077b858ULL) {
+ // Without SA_SIGINFO set, the return sequence is:
+ //
+ // __restore:
+ // 0x58 pop %eax
+ // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // struct sigcontext (same format as mcontext)
+ struct x86_mcontext_t context;
+ if (!memory->Read(sp() + 4, &context, sizeof(context))) {
+ return false;
+ }
+ regs_[X86_REG_EBP] = context.ebp;
+ regs_[X86_REG_ESP] = context.esp;
+ regs_[X86_REG_EBX] = context.ebx;
+ regs_[X86_REG_EDX] = context.edx;
+ regs_[X86_REG_ECX] = context.ecx;
+ regs_[X86_REG_EAX] = context.eax;
+ regs_[X86_REG_EIP] = context.eip;
+ SetFromRaw();
+ return true;
+ } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+ // With SA_SIGINFO set, the return sequence is:
+ //
+ // __restore_rt:
+ // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // siginfo*
+ // ucontext*
+
+ // Get the location of the sigcontext data.
+ uint32_t ptr;
+ if (!memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
+ return false;
+ }
+ // Only read the portion of the data structure we care about.
+ x86_ucontext_t x86_ucontext;
+ if (!memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_ucontext);
+ return true;
+ }
+ return false;
+}
+
+bool RegsX86_64::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+ return false;
+ }
+
+ uint16_t data2;
+ if (!memory->Read(pc() + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ return false;
+ }
+
+ // __restore_rt:
+ // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
+ // 0x0f 0x05 syscall
+ // 0x0f nopl 0x0($rax)
+
+ // Read the mcontext data from the stack.
+ // sp points to the ucontext data structure, read only the mcontext part.
+ x86_64_ucontext_t x86_64_ucontext;
+ if (!memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_64_ucontext);
+ return true;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
index 410af26..22f6a89 100644
--- a/libunwindstack/Ucontext.h
+++ b/libunwindstack/Ucontext.h
@@ -170,13 +170,13 @@
// Only care about the registers, skip everything else.
};
-typedef struct x86_64_ucontext {
+struct x86_64_ucontext_t {
uint64_t uc_flags; // unsigned long
uint64_t uc_link; // struct ucontext*
x86_64_stack_t uc_stack;
x86_64_mcontext_t uc_mcontext;
// Nothing else is used, so don't define it.
-} x86_64_ucontext_t;
+};
//-------------------------------------------------------------------
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index ab98f32..7623b7d 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -27,6 +27,8 @@
class Elf;
struct MapInfo;
class Memory;
+struct x86_ucontext_t;
+struct x86_64_ucontext_t;
class Regs {
public:
@@ -55,6 +57,8 @@
virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
+ virtual bool StepIfSignalHandler(Memory*) = 0;
+
virtual void SetFromRaw() = 0;
uint16_t sp_reg() { return sp_reg_; }
@@ -104,6 +108,8 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(Memory* memory) override;
};
class RegsArm64 : public RegsImpl<uint64_t> {
@@ -114,6 +120,8 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(Memory* memory) override;
};
class RegsX86 : public RegsImpl<uint32_t> {
@@ -124,6 +132,10 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(Memory* memory) override;
+
+ void SetFromUcontext(x86_ucontext_t* ucontext);
};
class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -134,6 +146,10 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(Memory* memory) override;
+
+ void SetFromUcontext(x86_64_ucontext_t* ucontext);
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 72ceb85..ed1be3b 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -26,6 +26,7 @@
#include <unwindstack/MapInfo.h>
#include "ElfTestUtils.h"
+#include "LogFake.h"
#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
@@ -131,6 +132,32 @@
ASSERT_FALSE(elf.Step(0, nullptr, nullptr));
}
+TEST_F(ElfTest, elf32_invalid_machine) {
+ Elf elf(memory_);
+
+ InitElf32(EM_PPC);
+
+ ResetLogs();
+ ASSERT_FALSE(elf.Init());
+
+ ASSERT_EQ("", GetFakeLogBuf());
+ ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
+ GetFakeLogPrint());
+}
+
+TEST_F(ElfTest, elf64_invalid_machine) {
+ Elf elf(memory_);
+
+ InitElf64(EM_PPC64);
+
+ ResetLogs();
+ ASSERT_FALSE(elf.Init());
+
+ ASSERT_EQ("", GetFakeLogBuf());
+ ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
+ GetFakeLogPrint());
+}
+
TEST_F(ElfTest, elf_arm) {
Elf elf(memory_);
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index e796c9b..f998da7 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -33,6 +33,7 @@
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool StepIfSignalHandler(Memory*) override { return false; }
bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; }
};
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3613689..9622166 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -23,6 +23,8 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Regs.h>
+#include "Machine.h"
+
#include "MemoryFake.h"
namespace unwindstack {
@@ -60,6 +62,7 @@
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool StepIfSignalHandler(Memory*) override { return false; }
};
class RegsTest : public ::testing::Test {
@@ -72,7 +75,10 @@
}
template <typename AddressType>
- void regs_return_address_register();
+ void RegsReturnAddressRegister();
+
+ void ArmStepIfSignalHandlerNonRt(uint32_t pc_data);
+ void ArmStepIfSignalHandlerRt(uint32_t pc_data);
ElfInterfaceFake* elf_interface_;
MemoryFake* memory_;
@@ -126,7 +132,7 @@
}
template <typename AddressType>
-void RegsTest::regs_return_address_register() {
+void RegsTest::RegsReturnAddressRegister() {
RegsTestImpl<AddressType> regs(20, 10, Regs::Location(Regs::LOCATION_REGISTER, 5));
regs[5] = 0x12345;
@@ -136,11 +142,11 @@
}
TEST_F(RegsTest, regs32_return_address_register) {
- regs_return_address_register<uint32_t>();
+ RegsReturnAddressRegister<uint32_t>();
}
TEST_F(RegsTest, regs64_return_address_register) {
- regs_return_address_register<uint64_t>();
+ RegsReturnAddressRegister<uint64_t>();
}
TEST_F(RegsTest, regs32_return_address_sp_offset) {
@@ -285,4 +291,160 @@
EXPECT_EQ(0x4900000000U, x86_64.pc());
}
+void RegsTest::ArmStepIfSignalHandlerNonRt(uint32_t pc_data) {
+ uint64_t addr = 0x1000;
+ RegsArm regs;
+ regs[ARM_REG_PC] = 0x5000;
+ regs[ARM_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData32(0x5000, pc_data);
+
+ for (uint64_t index = 0; index <= 30; index++) {
+ memory_->SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0x100U, regs[ARM_REG_SP]);
+ EXPECT_EQ(0x120U, regs[ARM_REG_PC]);
+ EXPECT_EQ(0x100U, regs.sp());
+ EXPECT_EQ(0x120U, regs.pc());
+}
+
+TEST_F(RegsTest, arm_step_if_signal_handler_non_rt) {
+ // Form 1
+ ArmStepIfSignalHandlerNonRt(0xe3a07077);
+
+ // Form 2
+ ArmStepIfSignalHandlerNonRt(0xef900077);
+
+ // Form 3
+ ArmStepIfSignalHandlerNonRt(0xdf002777);
+}
+
+void RegsTest::ArmStepIfSignalHandlerRt(uint32_t pc_data) {
+ uint64_t addr = 0x1000;
+ RegsArm regs;
+ regs[ARM_REG_PC] = 0x5000;
+ regs[ARM_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData32(0x5000, pc_data);
+
+ for (uint64_t index = 0; index <= 100; index++) {
+ memory_->SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0x350U, regs[ARM_REG_SP]);
+ EXPECT_EQ(0x370U, regs[ARM_REG_PC]);
+ EXPECT_EQ(0x350U, regs.sp());
+ EXPECT_EQ(0x370U, regs.pc());
+}
+
+TEST_F(RegsTest, arm_step_if_signal_handler_rt) {
+ // Form 1
+ ArmStepIfSignalHandlerRt(0xe3a070ad);
+
+ // Form 2
+ ArmStepIfSignalHandlerRt(0xef9000ad);
+
+ // Form 3
+ ArmStepIfSignalHandlerRt(0xdf0027ad);
+}
+
+TEST_F(RegsTest, arm64_step_if_signal_handler) {
+ uint64_t addr = 0x1000;
+ RegsArm64 regs;
+ regs[ARM64_REG_PC] = 0x8000;
+ regs[ARM64_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData64(0x8000, 0xd4000001d2801168ULL);
+
+ for (uint64_t index = 0; index <= 100; index++) {
+ memory_->SetData64(addr + index * 8, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0x460U, regs[ARM64_REG_SP]);
+ EXPECT_EQ(0x470U, regs[ARM64_REG_PC]);
+ EXPECT_EQ(0x460U, regs.sp());
+ EXPECT_EQ(0x470U, regs.pc());
+}
+
+TEST_F(RegsTest, x86_step_if_signal_handler_no_siginfo) {
+ uint64_t addr = 0xa00;
+ RegsX86 regs;
+ regs[X86_REG_EIP] = 0x4100;
+ regs[X86_REG_ESP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData64(0x4100, 0x80cd00000077b858ULL);
+ for (uint64_t index = 0; index <= 25; index++) {
+ memory_->SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0x70U, regs[X86_REG_EBP]);
+ EXPECT_EQ(0x80U, regs[X86_REG_ESP]);
+ EXPECT_EQ(0x90U, regs[X86_REG_EBX]);
+ EXPECT_EQ(0xa0U, regs[X86_REG_EDX]);
+ EXPECT_EQ(0xb0U, regs[X86_REG_ECX]);
+ EXPECT_EQ(0xc0U, regs[X86_REG_EAX]);
+ EXPECT_EQ(0xf0U, regs[X86_REG_EIP]);
+ EXPECT_EQ(0x80U, regs.sp());
+ EXPECT_EQ(0xf0U, regs.pc());
+}
+
+TEST_F(RegsTest, x86_step_if_signal_handler_siginfo) {
+ uint64_t addr = 0xa00;
+ RegsX86 regs;
+ regs[X86_REG_EIP] = 0x4100;
+ regs[X86_REG_ESP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData64(0x4100, 0x0080cd000000adb8ULL);
+ addr += 8;
+ // Pointer to ucontext data.
+ memory_->SetData32(addr, 0x8100);
+
+ addr = 0x8100;
+ for (uint64_t index = 0; index <= 30; index++) {
+ memory_->SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0xb0U, regs[X86_REG_EBP]);
+ EXPECT_EQ(0xc0U, regs[X86_REG_ESP]);
+ EXPECT_EQ(0xd0U, regs[X86_REG_EBX]);
+ EXPECT_EQ(0xe0U, regs[X86_REG_EDX]);
+ EXPECT_EQ(0xf0U, regs[X86_REG_ECX]);
+ EXPECT_EQ(0x100U, regs[X86_REG_EAX]);
+ EXPECT_EQ(0x130U, regs[X86_REG_EIP]);
+ EXPECT_EQ(0xc0U, regs.sp());
+ EXPECT_EQ(0x130U, regs.pc());
+}
+
+TEST_F(RegsTest, x86_64_step_if_signal_handler) {
+ uint64_t addr = 0x500;
+ RegsX86_64 regs;
+ regs[X86_64_REG_RIP] = 0x7000;
+ regs[X86_64_REG_RSP] = addr;
+ regs.SetFromRaw();
+
+ memory_->SetData64(0x7000, 0x0f0000000fc0c748);
+ memory_->SetData16(0x7008, 0x0f05);
+
+ for (uint64_t index = 0; index <= 30; index++) {
+ memory_->SetData64(addr + index * 8, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(memory_));
+ EXPECT_EQ(0x140U, regs[X86_64_REG_RSP]);
+ EXPECT_EQ(0x150U, regs[X86_64_REG_RIP]);
+ EXPECT_EQ(0x140U, regs.sp());
+ EXPECT_EQ(0x150U, regs.pc());
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 72065c9..3c69e2a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -30,6 +30,7 @@
#include <sstream>
#include <string>
#include <thread>
+#include <vector>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
@@ -42,16 +43,41 @@
static std::atomic_bool g_ready(false);
static volatile bool g_ready_for_remote = false;
+static volatile bool g_signal_ready_for_remote = false;
static std::atomic_bool g_finish(false);
static std::atomic_uintptr_t g_ucontext;
-static void Signal(int, siginfo_t*, void* sigcontext) {
+static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
+
+static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
+ "SignalOuterFunction", "InnerFunction",
+ "MiddleFunction", "OuterFunction"};
+
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
while (!g_finish.load()) {
}
}
-static std::string ErrorMsg(const char** function_names, size_t index,
+extern "C" void SignalInnerFunction() {
+ g_signal_ready_for_remote = true;
+ while (!g_finish.load()) {
+ }
+}
+
+extern "C" void SignalMiddleFunction() {
+ SignalInnerFunction();
+}
+
+extern "C" void SignalOuterFunction() {
+ SignalMiddleFunction();
+}
+
+static void SignalCallerHandler(int, siginfo_t*, void*) {
+ SignalOuterFunction();
+}
+
+static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index,
std::stringstream& unwind_stream) {
return std::string(
"Unwind completed without finding all frames\n"
@@ -59,10 +85,8 @@
function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
}
-static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs) {
- const char* function_names[] = {
- "InnerFunction", "MiddleFunction", "OuterFunction",
- };
+static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
+ std::vector<const char*>& function_names) {
size_t function_name_index = 0;
std::stringstream unwind_stream;
@@ -91,8 +115,7 @@
uint64_t func_offset;
if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
if (name == function_names[function_name_index]) {
- function_name_index++;
- if (function_name_index == sizeof(function_names) / sizeof(const char*)) {
+ if (++function_name_index == function_names.size()) {
return;
}
}
@@ -116,7 +139,7 @@
RegsGetLocal(regs.get());
MemoryLocal memory;
- VerifyUnwind(getpid(), &memory, &maps, regs.get());
+ VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
} else {
g_ready_for_remote = true;
g_ready = true;
@@ -137,6 +160,37 @@
OuterFunction(true);
}
+void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
+ *completed = false;
+ // Need to sleep before attempting first ptrace. Without this, on the
+ // host it becomes impossible to attach and ptrace set errno to EPERM.
+ usleep(1000);
+ for (size_t i = 0; i < 100; i++) {
+ ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
+ for (size_t j = 0; j < 100; j++) {
+ siginfo_t si;
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ MemoryRemote memory(pid);
+ // Read the remote value to see if we are ready.
+ bool value;
+ if (memory.Read(addr, &value, sizeof(value)) && value) {
+ *completed = true;
+ break;
+ }
+ }
+ usleep(1000);
+ }
+ if (leave_attached && *completed) {
+ break;
+ }
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+ if (*completed) {
+ break;
+ }
+ usleep(1000);
+ }
+}
+
TEST(UnwindTest, remote) {
pid_t pid;
if ((pid = fork()) == 0) {
@@ -145,31 +199,9 @@
}
ASSERT_NE(-1, pid);
- bool ready = false;
- uint64_t addr = reinterpret_cast<uint64_t>(&g_ready_for_remote);
- for (size_t i = 0; i < 100; i++) {
- ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
- for (size_t j = 0; j < 100; j++) {
- siginfo_t si;
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- // Check to see if process is ready to be unwound.
- MemoryRemote memory(pid);
- // Read the remote value to see if we are ready.
- bool value;
- if (memory.Read(addr, &value, sizeof(value)) && value) {
- ready = true;
- break;
- }
- }
- usleep(1000);
- }
- if (ready) {
- break;
- }
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
- usleep(1000);
- }
- ASSERT_TRUE(read) << "Timed out waiting for remote process to be ready.";
+ bool completed;
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -178,7 +210,7 @@
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
ASSERT_TRUE(regs.get() != nullptr);
- VerifyUnwind(pid, &memory, &maps, regs.get());
+ VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
@@ -195,7 +227,7 @@
struct sigaction act, oldact;
memset(&act, 0, sizeof(act));
- act.sa_sigaction = Signal;
+ act.sa_sigaction = SignalHandler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
// Wait for the tid to get set.
@@ -207,8 +239,7 @@
}
ASSERT_NE(0, tid.load());
// Portable tgkill method.
- ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Failed because "
- << strerror(errno);
+ ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
// Wait for context data.
void* ucontext;
@@ -226,7 +257,7 @@
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::GetMachineType(), ucontext));
MemoryLocal memory;
- VerifyUnwind(tid.load(), &memory, &maps, regs.get());
+ VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
@@ -234,4 +265,52 @@
thread.join();
}
+static void RemoteThroughSignal(unsigned int sa_flags) {
+ g_ready = false;
+ g_signal_ready_for_remote = false;
+ g_finish = false;
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ struct sigaction act, oldact;
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = SignalCallerHandler;
+ act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
+ ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+
+ OuterFunction(false);
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+
+ bool completed;
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_EQ(0, kill(pid, SIGUSR1));
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
+
+ RemoteMaps maps(pid);
+ ASSERT_TRUE(maps.Parse());
+ MemoryRemote memory(pid);
+ uint32_t machine_type;
+ std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+ ASSERT_TRUE(regs.get() != nullptr);
+
+ VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
+
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+
+ kill(pid, SIGKILL);
+ ASSERT_EQ(pid, wait(nullptr));
+}
+
+TEST(UnwindTest, remote_through_signal) {
+ RemoteThroughSignal(0);
+}
+
+TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+ RemoteThroughSignal(SA_SIGINFO);
+}
+
} // namespace unwindstack
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
index 3bb5430..e8f5c0b 100644
--- a/trusty/keymaster/trusty_keymaster_device_test.cpp
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -16,8 +16,8 @@
#include <algorithm>
#include <fstream>
-#include <UniquePtr.h>
#include <gtest/gtest.h>
+#include <nativehelper/UniquePtr.h>
#include <openssl/engine.h>
#include <hardware/keymaster0.h>