SQLiteCursor could be destroyed in Java object's finalize method, and UI...

SQLiteCursor could be destroyed in Java object's finalize method, and UI message loop might already shutdown, we need to check if the post task succeeds, then wait for callback.

BUG=239482

Review URL: https://chromiumcodereview.appspot.com/15701011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203953 0039d316-1c4b-4281-b951-d872f2087c98
parent 862bcc62
...@@ -132,7 +132,17 @@ jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) { ...@@ -132,7 +132,17 @@ jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
} }
void SQLiteCursor::Destroy(JNIEnv* env, jobject obj) { void SQLiteCursor::Destroy(JNIEnv* env, jobject obj) {
delete this; // We do our best to cleanup when Destroy() is called from Java's finalize()
// where the UI message loop might stop running or in the process of shutting
// down, as the whole process will be destroyed soon, it's fine to leave some
// objects out there.
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
DestroyOnUIThread();
} else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&SQLiteCursor::DestroyOnUIThread,
base::Unretained(this)))) {
delete this;
}
} }
SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names, SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
...@@ -150,25 +160,16 @@ SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names, ...@@ -150,25 +160,16 @@ SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
} }
SQLiteCursor::~SQLiteCursor() { SQLiteCursor::~SQLiteCursor() {
}
void SQLiteCursor::DestroyOnUIThread() {
// Consumer requests were set in the UI thread. They must be cancelled // Consumer requests were set in the UI thread. They must be cancelled
// using the same thread. // using the same thread.
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
CancelAllRequests(NULL); consumer_.reset();
} else { tracker_.reset();
base::WaitableEvent event(false, false); service_->CloseStatement(statement_);
BrowserThread::PostTask( delete this;
BrowserThread::UI,
FROM_HERE,
base::Bind(&SQLiteCursor::CancelAllRequests, base::Unretained(this),
&event));
event.Wait();
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&AndroidHistoryProviderService::CloseStatement,
base::Unretained(service_), statement_));
} }
bool SQLiteCursor::GetFavicon(chrome::FaviconID id, bool SQLiteCursor::GetFavicon(chrome::FaviconID id,
...@@ -226,17 +227,6 @@ void SQLiteCursor::OnMoved(AndroidHistoryProviderService::Handle handle, ...@@ -226,17 +227,6 @@ void SQLiteCursor::OnMoved(AndroidHistoryProviderService::Handle handle,
test_observer_->OnGetMoveToResult(); test_observer_->OnGetMoveToResult();
} }
void SQLiteCursor::CancelAllRequests(base::WaitableEvent* finished) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Destruction will cancel all pending tasks.
consumer_.reset();
tracker_.reset();
if (finished)
finished->Signal();
}
SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) { SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) {
if (column == statement_->favicon_index()) if (column == statement_->favicon_index())
return SQLiteCursor::BLOB; return SQLiteCursor::BLOB;
......
...@@ -136,6 +136,10 @@ class SQLiteCursor { ...@@ -136,6 +136,10 @@ class SQLiteCursor {
virtual ~SQLiteCursor(); virtual ~SQLiteCursor();
// Destory SQLiteCursor object on UI thread. All cleanup need finish in UI
// thread.
void DestroyOnUIThread();
// This method is for testing only. // This method is for testing only.
void set_test_observer(TestObserver* test_observer) { void set_test_observer(TestObserver* test_observer) {
test_observer_ = test_observer; test_observer_ = test_observer;
...@@ -155,9 +159,6 @@ class SQLiteCursor { ...@@ -155,9 +159,6 @@ class SQLiteCursor {
// The callback function of MoveTo(). // The callback function of MoveTo().
void OnMoved(AndroidHistoryProviderService::Handle handle, int pos); void OnMoved(AndroidHistoryProviderService::Handle handle, int pos);
// Used to cancel all request on the UI thread during shutdown.
void CancelAllRequests(base::WaitableEvent* finished);
JavaColumnType GetColumnTypeInternal(int column); JavaColumnType GetColumnTypeInternal(int column);
// Runs the MoveStatement on UI thread. // Runs the MoveStatement on UI thread.
......
...@@ -197,28 +197,25 @@ TEST_F(SQLiteCursorTest, Run) { ...@@ -197,28 +197,25 @@ TEST_F(SQLiteCursorTest, Run) {
FaviconService* favicon_service = new FaviconService(hs_); FaviconService* favicon_service = new FaviconService(hs_);
// Wraps cursor in a block, so the destructor will be called after that. SQLiteCursor* cursor = new SQLiteCursor(column_names, statement,
{ service_.get(), favicon_service);
SQLiteCursor cursor(column_names, statement, service_.get(), cursor->set_test_observer(this);
favicon_service); JNIEnv* env = base::android::AttachCurrentThread();
cursor.set_test_observer(this); EXPECT_EQ(1, cursor->GetCount(env, NULL));
JNIEnv* env = base::android::AttachCurrentThread(); EXPECT_EQ(0, cursor->MoveTo(env, NULL, 0));
EXPECT_EQ(1, cursor.GetCount(env, NULL)); EXPECT_EQ(row.url().spec(), base::android::ConvertJavaStringToUTF8(
EXPECT_EQ(0, cursor.MoveTo(env, NULL, 0)); cursor->GetString(env, NULL, 0)).c_str());
EXPECT_EQ(row.url().spec(), base::android::ConvertJavaStringToUTF8( EXPECT_EQ(history::ToDatabaseTime(row.last_visit_time()),
cursor.GetString(env, NULL, 0)).c_str()); cursor->GetLong(env, NULL, 1));
EXPECT_EQ(history::ToDatabaseTime(row.last_visit_time()), EXPECT_EQ(row.visit_count(), cursor->GetInt(env, NULL, 2));
cursor.GetLong(env, NULL, 1)); base::android::ScopedJavaLocalRef<jbyteArray> data =
EXPECT_EQ(row.visit_count(), cursor.GetInt(env, NULL, 2)); cursor->GetBlob(env, NULL, 3);
base::android::ScopedJavaLocalRef<jbyteArray> data = std::vector<uint8> out;
cursor.GetBlob(env, NULL, 3); base::android::JavaByteArrayToByteVector(env, data.obj(), &out);
std::vector<uint8> out; EXPECT_EQ(data_bytes->data().size(), out.size());
base::android::JavaByteArrayToByteVector(env, data.obj(), &out); EXPECT_EQ(data_bytes->data()[0], out[0]);
EXPECT_EQ(data_bytes->data().size(), out.size()); cursor->Destroy(env, NULL);
EXPECT_EQ(data_bytes->data()[0], out[0]); // Cursor::Destroy posts the task in UI thread, run Message loop to release
} // the statement, delete SQLiteCursor itself etc.
// Cursor's destructor post the task in UI thread, run Message loop to release
// the statement etc.
content::RunAllPendingInMessageLoop(); content::RunAllPendingInMessageLoop();
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment