Snap for 8730993 from fb02a510cffc20113785205a3130ca77b59ba08a to mainline-tzdata3-release
Change-Id: I89ed58150620bea80960b8591a4e8f01e618308a
diff --git a/Android.bp b/Android.bp
index 68457e5..77f126a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -48,9 +48,6 @@
"libc_malloc_debug_backtrace",
"libprocinfo",
],
- header_libs: [
- "libgtest_prod_headers",
- ],
export_include_dirs: ["include"],
local_include_dirs: ["include"],
version_script: "libmemunreachable.map",
@@ -64,9 +61,7 @@
"tests/MemUnreachable_test.cpp",
],
shared_libs: ["libmemunreachable"],
- header_libs: [
- "libbase_headers",
- ],
+
test_suites: ["device-tests"],
}
@@ -76,7 +71,6 @@
host_supported: true,
srcs: [
"tests/Allocator_test.cpp",
- "tests/AtomicState_test.cpp",
"tests/HeapWalker_test.cpp",
"tests/LeakFolding_test.cpp",
],
@@ -105,9 +99,7 @@
enabled: false,
},
},
- header_libs: [
- "libbase_headers",
- ],
+
test_suites: ["device-tests"],
}
diff --git a/AtomicState.h b/AtomicState.h
deleted file mode 100644
index 365eab9..0000000
--- a/AtomicState.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <chrono>
-#include <functional>
-#include <mutex>
-#include <unordered_set>
-
-#include <gtest/gtest_prod.h>
-
-#include "android-base/macros.h"
-
-namespace android {
-
-/*
- * AtomicState manages updating or waiting on a state enum between multiple threads.
- */
-template <typename T>
-class AtomicState {
- public:
- explicit AtomicState(T state) : state_(state) {}
- ~AtomicState() = default;
-
- /*
- * Set the state to `to`. Wakes up any waiters that are waiting on the new state.
- */
- void set(T to) {
- std::lock_guard<std::mutex> lock(m_);
- state_ = to;
- cv_.notify_all();
- }
-
- /*
- * If the state is `from`, change it to `to` and return true. Otherwise don't change
- * it and return false. If the state is changed, wakes up any waiters that are waiting
- * on the new state.
- */
- bool transition(T from, T to) {
- return transition_or(from, to, [&] { return state_; });
- }
-
- /*
- * If the state is `from`, change it to `to` and return true. Otherwise, call `or_func`,
- * set the state to the value it returns and return false. Wakes up any waiters that are
- * waiting on the new state.
- */
- bool transition_or(T from, T to, const std::function<T()>& orFunc) {
- std::lock_guard<std::mutex> lock(m_);
-
- bool failed = false;
- if (state_ == from) {
- state_ = to;
- } else {
- failed = true;
- state_ = orFunc();
- }
- cv_.notify_all();
-
- return !failed;
- }
-
- /*
- * Block until the state is either `state1` or `state2`, or the time limit is reached.
- * Returns true if the time limit was not reached, false if it was reached.
- */
- bool wait_for_either_of(T state1, T state2, std::chrono::milliseconds ms) {
- std::unique_lock<std::mutex> lock(m_);
- bool success = cv_.wait_for(lock, ms, [&] { return state_ == state1 || state_ == state2; });
- return success;
- }
-
- private:
- T state_;
- std::mutex m_;
- std::condition_variable cv_;
-
- FRIEND_TEST(AtomicStateTest, transition);
- FRIEND_TEST(AtomicStateTest, wait);
-
- DISALLOW_COPY_AND_ASSIGN(AtomicState);
-};
-
-} // namespace android
diff --git a/MemUnreachable.cpp b/MemUnreachable.cpp
index d37819a..b02a77e 100644
--- a/MemUnreachable.cpp
+++ b/MemUnreachable.cpp
@@ -29,7 +29,6 @@
#include <backtrace.h>
#include "Allocator.h"
-#include "AtomicState.h"
#include "Binder.h"
#include "HeapWalker.h"
#include "Leak.h"
@@ -38,6 +37,7 @@
#include "ProcessMappings.h"
#include "PtracerThread.h"
#include "ScopedDisableMalloc.h"
+#include "Semaphore.h"
#include "ThreadCapture.h"
#include "bionic.h"
@@ -282,13 +282,6 @@
return (val == 1) ? "" : "s";
}
-enum State {
- STARTING = 0,
- PAUSING,
- COLLECTING,
- ABORT,
-};
-
bool GetUnreachableMemory(UnreachableMemoryInfo& info, size_t limit) {
if (info.version > 0) {
MEM_ALOGE("unsupported UnreachableMemoryInfo.version %zu in GetUnreachableMemory",
@@ -301,7 +294,7 @@
Heap heap;
- AtomicState<State> state(STARTING);
+ Semaphore continue_parent_sem;
LeakPipe pipe;
PtracerThread thread{[&]() -> int {
@@ -310,13 +303,6 @@
/////////////////////////////////////////////
MEM_ALOGI("collecting thread info for process %d...", parent_pid);
- if (!state.transition_or(STARTING, PAUSING, [&] {
- MEM_ALOGI("collecting thread expected state STARTING, aborting");
- return ABORT;
- })) {
- return 1;
- }
-
ThreadCapture thread_capture(parent_pid, heap);
allocator::vector<ThreadInfo> thread_info(heap);
allocator::vector<Mapping> mappings(heap);
@@ -324,34 +310,24 @@
// ptrace all the threads
if (!thread_capture.CaptureThreads()) {
- state.set(ABORT);
+ continue_parent_sem.Post();
return 1;
}
// collect register contents and stacks
if (!thread_capture.CapturedThreadInfo(thread_info)) {
- state.set(ABORT);
+ continue_parent_sem.Post();
return 1;
}
// snapshot /proc/pid/maps
if (!ProcessMappings(parent_pid, mappings)) {
- state.set(ABORT);
+ continue_parent_sem.Post();
return 1;
}
if (!BinderReferences(refs)) {
- state.set(ABORT);
- return 1;
- }
-
- // Atomically update the state from PAUSING to COLLECTING.
- // The main thread may have given up waiting for this thread to finish
- // pausing, in which case it will have changed the state to ABORT.
- if (!state.transition_or(PAUSING, COLLECTING, [&] {
- MEM_ALOGI("collecting thread aborting");
- return ABORT;
- })) {
+ continue_parent_sem.Post();
return 1;
}
@@ -361,6 +337,7 @@
// can drop the malloc locks, it will block until the collection thread
// exits.
thread_capture.ReleaseThread(parent_tid);
+ continue_parent_sem.Post();
// fork a process to do the heap walking
int ret = fork();
@@ -423,15 +400,7 @@
// Wait for the collection thread to signal that it is ready to fork the
// heap walker process.
- if (!state.wait_for_either_of(COLLECTING, ABORT, 30s)) {
- // The pausing didn't finish within 30 seconds, attempt to atomically
- // update the state from PAUSING to ABORT. The collecting thread
- // may have raced with the timeout and already updated the state to
- // COLLECTING, in which case aborting is not necessary.
- if (state.transition(PAUSING, ABORT)) {
- MEM_ALOGI("main thread timed out waiting for collecting thread");
- }
- }
+ continue_parent_sem.Wait(30s);
// Re-enable malloc so the collection thread can fork.
}
diff --git a/OWNERS b/OWNERS
index e672416..9127a93 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,2 @@
-# Bug component: 391836
ccross@google.com
cferris@google.com
diff --git a/Semaphore.h b/Semaphore.h
new file mode 100644
index 0000000..cd73972
--- /dev/null
+++ b/Semaphore.h
@@ -0,0 +1,60 @@
+/*
+ * 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 LIBMEMUNREACHABLE_SEMAPHORE_H_
+#define LIBMEMUNREACHABLE_SEMAPHORE_H_
+
+#include <chrono>
+#include <mutex>
+
+#include "android-base/macros.h"
+
+namespace android {
+
+class Semaphore {
+ public:
+ explicit Semaphore(int count = 0) : count_(count) {}
+ ~Semaphore() = default;
+
+ void Wait(std::chrono::milliseconds ms) {
+ std::unique_lock<std::mutex> lk(m_);
+ cv_.wait_for(lk, ms, [&] {
+ if (count_ > 0) {
+ count_--;
+ return true;
+ }
+ return false;
+ });
+ }
+ void Post() {
+ {
+ std::lock_guard<std::mutex> lk(m_);
+ count_++;
+ }
+ cv_.notify_one();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Semaphore);
+
+ int count_;
+ std::mutex m_;
+ std::condition_variable cv_;
+};
+
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_SEMAPHORE_H_
diff --git a/TEST_MAPPING b/TEST_MAPPING
deleted file mode 100644
index 3ec91f8..0000000
--- a/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presubmit": [
- {
- "name": "memunreachable_test"
- },
- {
- "name": "memunreachable_unit_test"
- },
- {
- "name": "memunreachable_binder_test"
- }
- ]
-}
diff --git a/bionic.h b/bionic.h
index 49bf255..dd1ec79 100644
--- a/bionic.h
+++ b/bionic.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <sys/cdefs.h>
-#include <sys/types.h>
__BEGIN_DECLS
diff --git a/tests/AtomicState_test.cpp b/tests/AtomicState_test.cpp
deleted file mode 100644
index 7fb2806..0000000
--- a/tests/AtomicState_test.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2022 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 <AtomicState.h>
-
-#include <chrono>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-using namespace std::chrono_literals;
-
-namespace android {
-
-enum AtomicStateTestEnum {
- A,
- B,
- C,
- D,
- E,
-};
-
-class AtomicStateTest : public testing::Test {
- protected:
- AtomicStateTest() : state_(A) {}
- virtual void SetUp() {}
- virtual void TearDown() {}
-
- AtomicState<AtomicStateTestEnum> state_;
-};
-
-TEST_F(AtomicStateTest, transition) {
- ASSERT_EQ(A, state_.state_);
-
- // Starts as A, transition from B fails
- ASSERT_FALSE(state_.transition(B, C));
- ASSERT_EQ(A, state_.state_);
-
- // transition from A to B
- ASSERT_TRUE(state_.transition(A, B));
- ASSERT_EQ(B, state_.state_);
-
- // State is B, transition from A fails
- ASSERT_FALSE(state_.transition(A, B));
- ASSERT_EQ(B, state_.state_);
-
- // State is B, transition_or from A calls the lambda
- bool lambda = false;
- bool already_locked = false;
- state_.transition_or(A, B, [&] {
- // The lock should be held in the lambda
- if (state_.m_.try_lock()) {
- state_.m_.unlock();
- } else {
- already_locked = true;
- }
- lambda = true;
- return B;
- });
- ASSERT_TRUE(lambda);
- ASSERT_TRUE(already_locked);
- ASSERT_EQ(B, state_.state_);
-
- // State is C, transition_or from B to C does not call the lambda
- lambda = false;
- state_.transition_or(B, C, [&] {
- lambda = true;
- return C;
- });
- ASSERT_FALSE(lambda);
- ASSERT_EQ(C, state_.state_);
-}
-
-TEST_F(AtomicStateTest, wait) {
- ASSERT_EQ(A, state_.state_);
-
- // Starts as A, wait_for_either_of B, C returns false
- ASSERT_FALSE(state_.wait_for_either_of(B, C, 10ms));
-
- // Starts as A, wait_for_either_of A, B returns true
- ASSERT_TRUE(state_.wait_for_either_of(A, B, 1s));
-
- {
- std::thread t([&] {
- usleep(10000);
- state_.set(B);
- });
-
- // Wait ing for B or C returns true after state is set to B
- ASSERT_TRUE(state_.wait_for_either_of(B, C, 1s));
-
- t.join();
- }
-
- ASSERT_EQ(B, state_.state_);
- {
- std::thread t([&] {
- usleep(10000);
- state_.transition(B, C);
- });
-
- // Waiting for A or C returns true after state is transitioned to C
- ASSERT_TRUE(state_.wait_for_either_of(A, C, 1s));
-
- t.join();
- }
-
- ASSERT_EQ(C, state_.state_);
- {
- std::thread t([&] {
- usleep(10000);
- state_.transition(C, D);
- });
-
- // Waiting for A or B returns false after state is transitioned to D
- ASSERT_FALSE(state_.wait_for_either_of(A, B, 100ms));
-
- t.join();
- }
-}
-
-} // namespace android
diff --git a/tests/DisableMalloc_test.cpp b/tests/DisableMalloc_test.cpp
index ae560ed..f446719 100644
--- a/tests/DisableMalloc_test.cpp
+++ b/tests/DisableMalloc_test.cpp
@@ -19,8 +19,6 @@
#include <chrono>
#include <functional>
-#include <android-base/test_utils.h>
-
#include <ScopedDisableMalloc.h>
#include <gtest/gtest.h>
@@ -37,11 +35,6 @@
t.it_value.tv_usec = (us - s).count();
setitimer(ITIMER_REAL, &t, NULL);
}
-
- void SetUp() override {
- // HWASan does not support malloc_disable.
- SKIP_WITH_HWASAN;
- }
};
TEST_F(DisableMallocTest, reenable) {
diff --git a/tests/HeapWalker_test.cpp b/tests/HeapWalker_test.cpp
index f78fd66..9610cd6 100644
--- a/tests/HeapWalker_test.cpp
+++ b/tests/HeapWalker_test.cpp
@@ -25,14 +25,6 @@
namespace android {
-static inline uintptr_t UntagAddress(uintptr_t addr) {
-#if defined(__aarch64__)
- constexpr uintptr_t mask = (static_cast<uintptr_t>(1) << 56) - 1;
- addr = addr & mask;
-#endif
- return addr;
-}
-
class HeapWalkerTest : public ::testing::Test {
public:
HeapWalkerTest() : disable_malloc_(), heap_() {}
@@ -121,8 +113,8 @@
EXPECT_EQ(1U, num_leaks);
EXPECT_EQ(16U, leaked_bytes);
ASSERT_EQ(1U, leaked.size());
- EXPECT_EQ(UntagAddress(buffer_begin(buffer2)), leaked[0].begin);
- EXPECT_EQ(UntagAddress(buffer_end(buffer2)), leaked[0].end);
+ EXPECT_EQ(buffer_begin(buffer2), leaked[0].begin);
+ EXPECT_EQ(buffer_end(buffer2), leaked[0].end);
}
TEST_F(HeapWalkerTest, live) {
diff --git a/tests/MemUnreachable_test.cpp b/tests/MemUnreachable_test.cpp
index 8bc176b..9cb1623 100644
--- a/tests/MemUnreachable_test.cpp
+++ b/tests/MemUnreachable_test.cpp
@@ -19,8 +19,6 @@
#include <sys/prctl.h>
#include <unistd.h>
-#include <android-base/test_utils.h>
-
#include <gtest/gtest.h>
#include <memunreachable/memunreachable.h>
@@ -56,8 +54,6 @@
class MemunreachableTest : public ::testing::Test {
protected:
virtual void SetUp() {
- // HWASan does not support malloc_disable, which is required by memunreachable.
- SKIP_WITH_HWASAN;
CleanStack(8192);
CleanTcache();
}
@@ -248,7 +244,9 @@
TEST_F(MemunreachableTest, notdumpable) {
if (getuid() == 0) {
- GTEST_SKIP() << "Not testable when running as root";
+ // TODO(ccross): make this a skipped test when gtest supports them
+ printf("[ SKIP ] Not testable when running as root\n");
+ return;
}
ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0));