Merge "Rewrite bootctl utility to use new HAL interface"
diff --git a/f2fs_utils/f2fs_sparseblock.c b/f2fs_utils/f2fs_sparseblock.c
index e968ce0..d5c1f3a 100644
--- a/f2fs_utils/f2fs_sparseblock.c
+++ b/f2fs_utils/f2fs_sparseblock.c
@@ -2,17 +2,19 @@
#define LOG_TAG "f2fs_sparseblock"
-
-#include <cutils/log.h>
#include <errno.h>
-#include <fcntl.h>
#include <f2fs_fs.h>
+#include <fcntl.h>
#include <linux/types.h>
#include <malloc.h>
#include <string.h>
#include <sys/stat.h>
-#include "f2fs_sparseblock.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <log/log.h>
+
+#include "f2fs_sparseblock.h"
#define D_DISP_u32(ptr, member) \
do { \
diff --git a/memtrack/memtrack.cpp b/memtrack/memtrack.cpp
index 2c4d7c0..f14e06d 100644
--- a/memtrack/memtrack.cpp
+++ b/memtrack/memtrack.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "MemTracker"
#include "memtrack.h"
@@ -27,15 +28,10 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/log.h>
-
#include <algorithm>
#include <vector>
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "MemTracker"
+#include <android/log.h>
FileData::FileData(char *filename, char *buffer, size_t buffer_len)
: data_(buffer), max_(buffer_len), cur_idx_(0), len_(0),
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 9addd06..e993906 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -279,7 +279,7 @@
$($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OBJCOPY) --add-section .testzipdata=$$TMP_FILE $(linked_module) && \
rm -f $$TMP_FILE
-LOCAL_MULTILIB := first
+LOCAL_MULTILIB := both
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(LLVM_DEVICE_BUILD_MK)
include $(BUILD_NATIVE_TEST)
diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp
index 90bb4fa..dc7a4da 100644
--- a/simpleperf/IOEventLoop_test.cpp
+++ b/simpleperf/IOEventLoop_test.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest.h>
+#include <atomic>
#include <chrono>
#include <thread>
@@ -105,13 +106,15 @@
}
return true;
}));
- std::thread thread([]() {
- for (int i = 0; i < 100; ++i) {
+ std::atomic<bool> stop_thread(false);
+ std::thread thread([&]() {
+ while (!stop_thread) {
usleep(1000);
kill(getpid(), SIGINT);
}
});
ASSERT_TRUE(loop.RunLoop());
+ stop_thread = true;
thread.join();
ASSERT_EQ(100, count);
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index b863f01..35f330e 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -141,10 +141,13 @@
TEST(record_cmd, dwarf_callchain_sampling) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf"}));
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf,16384"}));
- ASSERT_FALSE(RunRecordCmd({"--call-graph", "dwarf,65536"}));
- ASSERT_TRUE(RunRecordCmd({"-g"}));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf"}));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,16384"}));
+ ASSERT_FALSE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,65536"}));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}));
} else {
GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
"not supported on this device.";
@@ -172,7 +175,10 @@
TEST(record_cmd, post_unwind_option) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--post-unwind"}));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf", "--post-unwind"}));
} else {
GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
"not supported on this device.";
@@ -291,11 +297,14 @@
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RunRecordCmd({"-g"}, tmpfile.path));
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}, tmpfile.path));
bool success;
CheckDsoSymbolRecords(tmpfile.path, false, &success);
ASSERT_TRUE(success);
- ASSERT_TRUE(RunRecordCmd({"-g", "--dump-symbols"}, tmpfile.path));
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g", "--dump-symbols"}, tmpfile.path));
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index 98190ee..f34be5c 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -446,9 +446,12 @@
TEST_F(ReportCommandTest, dwarf_callgraph) {
if (IsDwarfCallChainSamplingSupported()) {
+ std::vector<std::unique_ptr<Workload>> workloads;
+ CreateProcesses(1, &workloads);
+ std::string pid = std::to_string(workloads[0]->GetPid());
TemporaryFile tmp_file;
ASSERT_TRUE(
- RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
+ RecordCmd()->Run({"-p", pid, "-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
ReportRaw(tmp_file.path, {"-g"});
ASSERT_TRUE(success);
} else {
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 25fcaf9..125f938 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -55,9 +55,15 @@
void CreateProcesses(size_t count,
std::vector<std::unique_ptr<Workload>>* workloads) {
workloads->clear();
+ // Create workloads run longer than profiling time.
+ auto function = []() {
+ while (true) {
+ for (volatile int i = 0; i < 10000; ++i);
+ usleep(1);
+ }
+ };
for (size_t i = 0; i < count; ++i) {
- // Create a workload runs longer than profiling time.
- auto workload = Workload::CreateWorkload({"sleep", "1000"});
+ auto workload = Workload::CreateWorkload(function);
ASSERT_TRUE(workload != nullptr);
ASSERT_TRUE(workload->Start());
workloads->push_back(std::move(workload));
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index c889416..d52c445 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -118,14 +118,18 @@
build_id_map_ = std::move(map);
}
-BuildId Dso::GetExpectedBuildId() {
- auto it = build_id_map_.find(path_);
+BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
+ auto it = build_id_map_.find(path);
if (it != build_id_map_.end()) {
return it->second;
}
return BuildId();
}
+BuildId Dso::GetExpectedBuildId() {
+ return FindExpectedBuildIdForPath(path_);
+}
+
std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type,
const std::string& dso_path) {
return std::unique_ptr<Dso>(new Dso(dso_type, dso_path));
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index 17b3988..7102f0e 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -92,6 +92,7 @@
}
static void SetBuildIds(
const std::vector<std::pair<std::string, BuildId>>& build_ids);
+ static BuildId FindExpectedBuildIdForPath(const std::string& path);
static std::unique_ptr<Dso> CreateDso(DsoType dso_type,
const std::string& dso_path);
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp
index 2aa0ccc..abd0962 100644
--- a/simpleperf/report_lib_interface.cpp
+++ b/simpleperf/report_lib_interface.cpp
@@ -51,6 +51,7 @@
const char* dso_name;
uint64_t vaddr_in_file;
const char* symbol_name;
+ uint64_t symbol_addr;
};
struct CallChainEntry {
@@ -80,6 +81,8 @@
Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
+
+const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
}
struct EventAttrWithName {
@@ -122,8 +125,11 @@
SymbolEntry* GetSymbolOfCurrentSample();
CallChain* GetCallChainOfCurrentSample();
+ const char* GetBuildIdForPath(const char* path);
+
private:
Sample* GetCurrentSample();
+ bool OpenRecordFileIfNecessary();
std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
std::string record_filename_;
@@ -136,6 +142,7 @@
SymbolEntry current_symbol_;
CallChain current_callchain_;
std::vector<CallChainEntry> callchain_entries_;
+ std::string build_id_string_;
int update_flag_;
std::vector<EventAttrWithName> event_attrs_;
};
@@ -161,15 +168,21 @@
return true;
}
-
-Sample* ReportLib::GetNextSample() {
+bool ReportLib::OpenRecordFileIfNecessary() {
if (record_file_reader_ == nullptr) {
record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
if (record_file_reader_ == nullptr) {
- return nullptr;
+ return false;
}
record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_);
}
+ return true;
+}
+
+Sample* ReportLib::GetNextSample() {
+ if (!OpenRecordFileIfNecessary()) {
+ return nullptr;
+ }
while (true) {
std::unique_ptr<Record> record;
if (!record_file_reader_->ReadRecord(record)) {
@@ -236,6 +249,7 @@
current_symbol_.dso_name = map->dso->Path().c_str();
current_symbol_.vaddr_in_file = vaddr_in_file;
current_symbol_.symbol_name = symbol->DemangledName();
+ current_symbol_.symbol_addr = symbol->addr;
update_flag_ |= UPDATE_FLAG_OF_SYMBOL;
}
return ¤t_symbol_;
@@ -281,6 +295,7 @@
entry.symbol.dso_name = map->dso->Path().c_str();
entry.symbol.vaddr_in_file = vaddr_in_file;
entry.symbol.symbol_name = symbol->DemangledName();
+ entry.symbol.symbol_addr = symbol->addr;
callchain_entries_.push_back(entry);
}
}
@@ -292,6 +307,20 @@
return ¤t_callchain_;
}
+const char* ReportLib::GetBuildIdForPath(const char* path) {
+ if (!OpenRecordFileIfNecessary()) {
+ build_id_string_.clear();
+ return build_id_string_.c_str();
+ }
+ BuildId build_id = Dso::FindExpectedBuildIdForPath(path);
+ if (build_id.IsEmpty()) {
+ build_id_string_.clear();
+ } else {
+ build_id_string_ = build_id.ToString();
+ }
+ return build_id_string_.c_str();
+}
+
// Exported methods working with a client created instance
ReportLib* CreateReportLib() {
return new ReportLib();
@@ -336,3 +365,7 @@
CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) {
return report_lib->GetCallChainOfCurrentSample();
}
+
+const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
+ return report_lib->GetBuildIdForPath(path);
+}
diff --git a/simpleperf/scripts/libsimpleperf_report.so b/simpleperf/scripts/libsimpleperf_report.so
index ee3bff3..8682534 100755
--- a/simpleperf/scripts/libsimpleperf_report.so
+++ b/simpleperf/scripts/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
index 05ad8f0..1ccecdc 100644
--- a/simpleperf/scripts/simpleperf_report_lib.py
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -21,14 +21,16 @@
import ctypes as ct
import os
+import subprocess
import sys
+import unittest
def _isWindows():
return sys.platform == 'win32' or sys.platform == 'cygwin'
-def _get_script_path():
+def _get_script_dir():
return os.path.dirname(os.path.realpath(__file__))
@@ -40,7 +42,7 @@
else:
so_name = 'libsimpleperf_report.so'
- return os.path.join(_get_script_path(), so_name)
+ return os.path.join(_get_script_dir(), so_name)
def _is_null(p):
@@ -55,6 +57,13 @@
return str.encode('utf-8')
+def _char_pt_to_str(char_pt):
+ if sys.version_info < (3, 0):
+ return char_pt
+ return char_pt.decode('utf-8')
+
+
+# TODO: convert fields of type c_char_p into str for python3.
class SampleStruct(ct.Structure):
_fields_ = [('ip', ct.c_uint64),
('pid', ct.c_uint32),
@@ -73,7 +82,8 @@
class SymbolStruct(ct.Structure):
_fields_ = [('dso_name', ct.c_char_p),
('vaddr_in_file', ct.c_uint64),
- ('symbol_name', ct.c_char_p)]
+ ('symbol_name', ct.c_char_p),
+ ('symbol_addr', ct.c_uint64)]
class CallChainEntryStructure(ct.Structure):
@@ -114,6 +124,8 @@
self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
CallChainStructure)
+ self._GetBuildIdForPathFunc = self._lib.GetBuildIdForPath
+ self._GetBuildIdForPathFunc.restype = ct.c_char_p
self._instance = self._CreateReportLibFunc()
assert(not _is_null(self._instance))
@@ -175,6 +187,11 @@
assert(not _is_null(callchain))
return callchain
+ def GetBuildIdForPath(self, path):
+ build_id = self._GetBuildIdForPathFunc(self.getInstance(), _char_pt(path))
+ assert(not _is_null(build_id))
+ return _char_pt_to_str(build_id)
+
def getInstance(self):
if self._instance is None:
raise Exception("Instance is Closed")
@@ -183,3 +200,51 @@
def _check(self, cond, failmsg):
if not cond:
raise Exception(failmsg)
+
+
+class TestReportLib(unittest.TestCase):
+ def setUp(self):
+ self.perf_data_path = os.path.join(os.path.dirname(_get_script_dir()),
+ 'testdata', 'perf_with_symbols.data')
+ if not os.path.isfile(self.perf_data_path):
+ raise Exception("can't find perf_data at %s" % self.perf_data_path)
+ self.report_lib = ReportLib()
+ self.report_lib.SetRecordFile(self.perf_data_path)
+
+ def tearDown(self):
+ self.report_lib.Close()
+
+ def test_build_id(self):
+ build_id = self.report_lib.GetBuildIdForPath('/data/t2')
+ self.assertEqual(build_id, '0x70f1fe24500fc8b0d9eb477199ca1ca21acca4de')
+
+ def test_symbol_addr(self):
+ met_func2 = False
+ while True:
+ sample = self.report_lib.GetNextSample()
+ if sample is None:
+ break
+ event = self.report_lib.GetEventOfCurrentSample()
+ symbol = self.report_lib.GetSymbolOfCurrentSample()
+ symbol_name = _char_pt_to_str(symbol[0].symbol_name)
+ if symbol_name == 'func2(int, int)':
+ met_func2 = True
+ self.assertEqual(symbol[0].symbol_addr, 0x4004ed)
+ self.assertTrue(met_func2)
+
+
+def main():
+ test_all = True
+ if len(sys.argv) > 1 and sys.argv[1] == '--test-one':
+ test_all = False
+ del sys.argv[1]
+
+ if test_all:
+ subprocess.check_call(['python', os.path.realpath(__file__), '--test-one'])
+ subprocess.check_call(['python3', os.path.realpath(__file__), '--test-one'])
+ else:
+ sys.exit(unittest.main())
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/simpleperf/workload.cpp b/simpleperf/workload.cpp
index 1d34c11..dcb0e78 100644
--- a/simpleperf/workload.cpp
+++ b/simpleperf/workload.cpp
@@ -25,7 +25,15 @@
#include <android-base/logging.h>
std::unique_ptr<Workload> Workload::CreateWorkload(const std::vector<std::string>& args) {
- std::unique_ptr<Workload> workload(new Workload(args));
+ std::unique_ptr<Workload> workload(new Workload(args, std::function<void ()>()));
+ if (workload != nullptr && workload->CreateNewProcess()) {
+ return workload;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<Workload> Workload::CreateWorkload(const std::function<void ()>& function) {
+ std::unique_ptr<Workload> workload(new Workload(std::vector<std::string>(), function));
if (workload != nullptr && workload->CreateNewProcess()) {
return workload;
}
@@ -47,8 +55,6 @@
}
}
-static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd);
-
bool Workload::CreateNewProcess() {
CHECK_EQ(work_state_, NotYetCreateNewProcess);
@@ -78,7 +84,7 @@
// In child process.
close(start_signal_pipe[1]);
close(exec_child_pipe[0]);
- ChildProcessFn(args_, start_signal_pipe[0], exec_child_pipe[1]);
+ ChildProcessFn(start_signal_pipe[0], exec_child_pipe[1]);
_exit(0);
}
// In parent process.
@@ -91,28 +97,33 @@
return true;
}
-static void ChildProcessFn(std::vector<std::string>& args, int start_signal_fd, int exec_child_fd) {
+void Workload::ChildProcessFn(int start_signal_fd, int exec_child_fd) {
// Die if parent exits.
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
- std::vector<char*> argv(args.size() + 1);
- for (size_t i = 0; i < args.size(); ++i) {
- argv[i] = &args[i][0];
- }
- argv[args.size()] = nullptr;
char start_signal = 0;
ssize_t nread = TEMP_FAILURE_RETRY(read(start_signal_fd, &start_signal, 1));
if (nread == 1 && start_signal == 1) {
close(start_signal_fd);
- execvp(argv[0], argv.data());
- // If execvp() succeed, we will not arrive here. But if it failed, we need to
- // report the failure to the parent process by writing 1 to exec_child_fd.
- int saved_errno = errno;
- char exec_child_failed = 1;
- TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1));
- close(exec_child_fd);
- errno = saved_errno;
- PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")";
+ if (child_proc_function_) {
+ close(exec_child_fd);
+ child_proc_function_();
+ } else {
+ char* argv[child_proc_args_.size() + 1];
+ for (size_t i = 0; i < child_proc_args_.size(); ++i) {
+ argv[i] = &child_proc_args_[i][0];
+ }
+ argv[child_proc_args_.size()] = nullptr;
+ execvp(argv[0], argv);
+ // If execvp() succeed, we will not arrive here. But if it failed, we need to
+ // report the failure to the parent process by writing 1 to exec_child_fd.
+ int saved_errno = errno;
+ char exec_child_failed = 1;
+ TEMP_FAILURE_RETRY(write(exec_child_fd, &exec_child_failed, 1));
+ close(exec_child_fd);
+ errno = saved_errno;
+ PLOG(ERROR) << "child process failed to execvp(" << argv[0] << ")";
+ }
} else {
PLOG(ERROR) << "child process failed to receive start_signal, nread = " << nread;
}
diff --git a/simpleperf/workload.h b/simpleperf/workload.h
index fa754b5..2141830 100644
--- a/simpleperf/workload.h
+++ b/simpleperf/workload.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <chrono>
+#include <functional>
#include <string>
#include <vector>
@@ -34,6 +35,7 @@
public:
static std::unique_ptr<Workload> CreateWorkload(const std::vector<std::string>& args);
+ static std::unique_ptr<Workload> CreateWorkload(const std::function<void ()>& function);
~Workload();
@@ -43,19 +45,24 @@
}
private:
- explicit Workload(const std::vector<std::string>& args)
+ explicit Workload(const std::vector<std::string>& args,
+ const std::function<void ()>& function)
: work_state_(NotYetCreateNewProcess),
- args_(args),
+ child_proc_args_(args),
+ child_proc_function_(function),
work_pid_(-1),
start_signal_fd_(-1),
exec_child_fd_(-1) {
}
bool CreateNewProcess();
+ void ChildProcessFn(int start_signal_fd, int exec_child_fd);
bool WaitChildProcess(bool wait_forever, bool is_child_killed);
WorkState work_state_;
- std::vector<std::string> args_;
+ // The child process either executes child_proc_args or run child_proc_function.
+ std::vector<std::string> child_proc_args_;
+ std::function<void ()> child_proc_function_;
pid_t work_pid_;
int start_signal_fd_; // The parent process writes 1 to start workload in the child process.
int exec_child_fd_; // The child process writes 1 to notify that execvp() failed.
diff --git a/tests/lib/testUtil/testUtil.c b/tests/lib/testUtil/testUtil.c
index d4dcea2..83dd946 100644
--- a/tests/lib/testUtil/testUtil.c
+++ b/tests/lib/testUtil/testUtil.c
@@ -25,12 +25,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
-
#include <sys/time.h>
#include <sys/wait.h>
+#include <time.h>
-#include <cutils/log.h>
+#include <android/log.h>
#define ALEN(a) (sizeof(a) / sizeof((a)[0])) // Array length
typedef unsigned int bool_t;
diff --git a/tests/timetest/Android.mk b/tests/timetest/Android.mk
index 92bbf1e..b644894 100644
--- a/tests/timetest/Android.mk
+++ b/tests/timetest/Android.mk
@@ -3,20 +3,12 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= timetest.c
-
-LOCAL_MODULE:= timetest
-
-LOCAL_MODULE_TAGS := optional
-
+LOCAL_SRC_FILES := timetest.c
+LOCAL_MODULE := timetest
+LOCAL_MODULE_TAGS := tests
LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
-
LOCAL_STATIC_LIBRARIES := libc
-
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
# -----------------------------------------------------------------------------
# Unit tests.