153 lines
5.1 KiB
C++
153 lines
5.1 KiB
C++
// Copyright 2019 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/android/java_handler_thread.h"
|
|
|
|
#include "base/synchronization/waitable_event.h"
|
|
#include "base/task/sequence_manager/sequence_manager_impl.h"
|
|
#include "base/task/task_observer.h"
|
|
#include "base/test/android/java_handler_thread_helpers.h"
|
|
#include "base/test/bind.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace base {
|
|
namespace {
|
|
|
|
class JavaHandlerThreadForTest : public android::JavaHandlerThread {
|
|
public:
|
|
explicit JavaHandlerThreadForTest(
|
|
const char* name,
|
|
base::ThreadType thread_type = base::ThreadType::kDefault)
|
|
: android::JavaHandlerThread(name, thread_type) {}
|
|
|
|
using android::JavaHandlerThread::state;
|
|
using android::JavaHandlerThread::State;
|
|
};
|
|
|
|
class DummyTaskObserver : public TaskObserver {
|
|
public:
|
|
explicit DummyTaskObserver(int num_tasks)
|
|
: num_tasks_started_(0), num_tasks_processed_(0), num_tasks_(num_tasks) {}
|
|
|
|
DummyTaskObserver(int num_tasks, int num_tasks_started)
|
|
: num_tasks_started_(num_tasks_started),
|
|
num_tasks_processed_(0),
|
|
num_tasks_(num_tasks) {}
|
|
|
|
DummyTaskObserver(const DummyTaskObserver&) = delete;
|
|
DummyTaskObserver& operator=(const DummyTaskObserver&) = delete;
|
|
|
|
~DummyTaskObserver() override = default;
|
|
|
|
void WillProcessTask(const PendingTask& /* pending_task */,
|
|
bool /* was_blocked_or_low_priority */) override {
|
|
num_tasks_started_++;
|
|
EXPECT_LE(num_tasks_started_, num_tasks_);
|
|
EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
|
|
}
|
|
|
|
void DidProcessTask(const PendingTask& pending_task) override {
|
|
num_tasks_processed_++;
|
|
EXPECT_LE(num_tasks_started_, num_tasks_);
|
|
EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
|
|
}
|
|
|
|
int num_tasks_started() const { return num_tasks_started_; }
|
|
int num_tasks_processed() const { return num_tasks_processed_; }
|
|
|
|
private:
|
|
int num_tasks_started_;
|
|
int num_tasks_processed_;
|
|
const int num_tasks_;
|
|
};
|
|
|
|
void PostNTasks(int posts_remaining) {
|
|
if (posts_remaining > 1) {
|
|
SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE, BindOnce(&PostNTasks, posts_remaining - 1));
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class JavaHandlerThreadTest : public ::testing::Test {};
|
|
|
|
void RunTest_AbortDontRunMoreTasks(bool delayed, bool init_java_first) {
|
|
WaitableEvent test_done_event;
|
|
std::unique_ptr<android::JavaHandlerThread> java_thread;
|
|
if (init_java_first) {
|
|
java_thread = android::JavaHandlerThreadHelpers::CreateJavaFirst();
|
|
} else {
|
|
java_thread = std::make_unique<android::JavaHandlerThread>(
|
|
"JavaHandlerThreadForTesting from AbortDontRunMoreTasks");
|
|
}
|
|
java_thread->Start();
|
|
java_thread->ListenForUncaughtExceptionsForTesting();
|
|
|
|
auto target =
|
|
BindOnce(&android::JavaHandlerThreadHelpers::ThrowExceptionAndAbort,
|
|
&test_done_event);
|
|
if (delayed) {
|
|
java_thread->task_runner()->PostDelayedTask(FROM_HERE, std::move(target),
|
|
Milliseconds(10));
|
|
} else {
|
|
java_thread->task_runner()->PostTask(FROM_HERE, std::move(target));
|
|
java_thread->task_runner()->PostTask(FROM_HERE,
|
|
MakeExpectedNotRunClosure(FROM_HERE));
|
|
}
|
|
test_done_event.Wait();
|
|
java_thread->Stop();
|
|
android::ScopedJavaLocalRef<jthrowable> exception =
|
|
java_thread->GetUncaughtExceptionIfAny();
|
|
ASSERT_TRUE(
|
|
android::JavaHandlerThreadHelpers::IsExceptionTestException(exception));
|
|
}
|
|
|
|
TEST_F(JavaHandlerThreadTest, JavaExceptionAbort) {
|
|
constexpr bool delayed = false;
|
|
constexpr bool init_java_first = false;
|
|
RunTest_AbortDontRunMoreTasks(delayed, init_java_first);
|
|
}
|
|
|
|
TEST_F(JavaHandlerThreadTest, DelayedJavaExceptionAbort) {
|
|
constexpr bool delayed = true;
|
|
constexpr bool init_java_first = false;
|
|
RunTest_AbortDontRunMoreTasks(delayed, init_java_first);
|
|
}
|
|
|
|
TEST_F(JavaHandlerThreadTest, JavaExceptionAbortInitJavaFirst) {
|
|
constexpr bool delayed = false;
|
|
constexpr bool init_java_first = true;
|
|
RunTest_AbortDontRunMoreTasks(delayed, init_java_first);
|
|
}
|
|
|
|
TEST_F(JavaHandlerThreadTest, RunTasksWhileShuttingDownJavaThread) {
|
|
const int kNumPosts = 6;
|
|
DummyTaskObserver observer(kNumPosts, 1);
|
|
|
|
auto java_thread = std::make_unique<JavaHandlerThreadForTest>("test");
|
|
java_thread->Start();
|
|
|
|
sequence_manager::internal::SequenceManagerImpl* sequence_manager =
|
|
static_cast<sequence_manager::internal::SequenceManagerImpl*>(
|
|
java_thread->state()->sequence_manager.get());
|
|
|
|
java_thread->task_runner()->PostTask(
|
|
FROM_HERE, BindLambdaForTesting([&]() {
|
|
sequence_manager->AddTaskObserver(&observer);
|
|
SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
|
|
FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE), Days(1));
|
|
java_thread->StopSequenceManagerForTesting();
|
|
PostNTasks(kNumPosts);
|
|
}));
|
|
|
|
java_thread->JoinForTesting();
|
|
java_thread.reset();
|
|
|
|
EXPECT_EQ(kNumPosts, observer.num_tasks_started());
|
|
EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
|
|
}
|
|
|
|
} // namespace base
|