Bug 1638256 - Use mTelemetryFilename for the mozStorage thread name. r=asuth

Depends on D181037

Differential Revision: https://phabricator.services.mozilla.com/D181038
This commit is contained in:
Marco Bonardo 2023-06-24 10:11:28 +00:00
parent 81f54fd826
commit 95fe144ede
8 changed files with 313 additions and 5 deletions

View File

@ -18,6 +18,21 @@ interface nsIPropertyBag2;
interface nsIVariant;
interface mozIStorageCompletionCallback;
/**
* PRIVACY WARNING
* ===============
*
* Database file names can be exposed through telemetry and in crash reports on
* the https://crash-stats.mozilla.org site, to allow recognizing the affected
* database.
* if your database name may contain privacy sensitive information, e.g. an
* URL origin, you should use openDatabaseWithFileURL and pass an explicit
* TelemetryFilename to it. That name will be used both for telemetry and for
* thread names in crash reports.
* If you have different needs (e.g. using the javascript module or an async
* connection from the main thread) please coordinate with the mozStorage peers.
*/
/**
* The mozIStorageService interface is intended to be implemented by
* a service that can create storage connections (mozIStorageConnection)

View File

@ -707,8 +707,15 @@ nsIEventTarget* Connection::getAsyncExecutionTarget() {
// Create the async event target if there's none yet.
if (!mAsyncExecutionThread) {
// Names start with "sqldb:" followed by a recognizable name, like the
// database file name, or a specially crafted name like "memory".
// This name will be surfaced on https://crash-stats.mozilla.org, so any
// sensitive part of the file name (e.g. an URL origin) should be replaced
// by passing an explicit telemetryName to openDatabaseWithFileURL.
nsAutoCString name("sqldb:"_ns);
name.Append(mTelemetryFilename);
static nsThreadPoolNaming naming;
nsresult rv = NS_NewNamedThread(naming.GetNextThreadName("mozStorage"),
nsresult rv = NS_NewNamedThread(naming.GetNextThreadName(name),
getter_AddRefs(mAsyncExecutionThread));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create async thread.");

View File

@ -467,8 +467,9 @@ Service::OpenSpecialDatabase(const nsACString& aStorageKey,
flags |= SQLITE_OPEN_URI;
}
RefPtr<Connection> msc = new Connection(this, flags, Connection::SYNCHRONOUS,
":memory:"_ns, interruptible);
RefPtr<Connection> msc =
new Connection(this, flags, Connection::SYNCHRONOUS,
kMozStorageMemoryStorageKey, interruptible);
const nsresult rv = msc->initialize(aStorageKey, aName);
NS_ENSURE_SUCCESS(rv, rv);
@ -589,7 +590,7 @@ Service::OpenAsyncDatabase(nsIVariant* aDatabaseStore, uint32_t aOpenFlags,
// Create connection on this thread, but initialize it on its helper thread.
nsAutoCString telemetryFilename;
if (!storageFile) {
telemetryFilename.AssignLiteral("memory");
telemetryFilename.Assign(kMozStorageMemoryStorageKey);
} else {
rv = storageFile->GetNativeLeafName(telemetryFilename);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
"storage_test_harness.cpp",
"test_AsXXX_helpers.cpp",
"test_async_callbacks_with_spun_event_loops.cpp",
"test_async_thread_naming.cpp",
"test_asyncStatementExecution_transaction.cpp",
"test_binding_params.cpp",
"test_file_perms.cpp",

View File

@ -105,6 +105,28 @@ void AsyncStatementSpinner::SpinUntilCompleted() {
#define NS_DECL_ASYNCSTATEMENTSPINNER \
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) override;
NS_IMPL_ISUPPORTS(AsyncCompletionSpinner, mozIStorageCompletionCallback)
AsyncCompletionSpinner::AsyncCompletionSpinner()
: mCompletionReason(NS_OK), mCompleted(false) {}
NS_IMETHODIMP
AsyncCompletionSpinner::Complete(nsresult reason, nsISupports* value) {
mCompleted = true;
mCompletionReason = reason;
mCompletionValue = value;
return NS_OK;
}
void AsyncCompletionSpinner::SpinUntilCompleted() {
nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
nsresult rv = NS_OK;
bool processed = true;
while (!mCompleted && NS_SUCCEEDED(rv)) {
rv = thread->ProcessNextEvent(true, &processed);
}
}
////////////////////////////////////////////////////////////////////////////////
//// Async Helpers

View File

@ -66,7 +66,24 @@ class AsyncStatementSpinner : public mozIStorageStatementCallback,
uint16_t completionReason;
protected:
virtual ~AsyncStatementSpinner() {}
virtual ~AsyncStatementSpinner() = default;
volatile bool mCompleted;
};
class AsyncCompletionSpinner : public mozIStorageCompletionCallback {
public:
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
AsyncCompletionSpinner();
void SpinUntilCompleted();
nsresult mCompletionReason;
nsCOMPtr<nsISupports> mCompletionValue;
protected:
virtual ~AsyncCompletionSpinner() = default;
volatile bool mCompleted;
};

View File

@ -0,0 +1,230 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsVariant.h"
#include "storage_test_harness.h"
#include "nsThreadUtils.h"
#include "nsIURI.h"
#include "nsIFileURL.h"
#include "nsIVariant.h"
#include "nsNetUtil.h"
////////////////////////////////////////////////////////////////////////////////
//// Tests
TEST(storage_async_thread_naming, MemoryDatabase)
{
HookSqliteMutex hook;
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
nsCOMPtr<nsIThread> target(get_conn_async_thread(db));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
printf("%s", name.get());
do_check_true(StringBeginsWith(name, "sqldb:memory"_ns));
blocking_async_close(db);
}
TEST(storage_async_thread_naming, FileDatabase)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
do_check_success(ss->OpenDatabase(dbFile, 0, getter_AddRefs(conn)));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
{
nsCOMPtr<mozIStorageConnection> clone;
do_check_success(conn->Clone(true, getter_AddRefs(clone)));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(clone);
}
blocking_async_close(conn);
}
TEST(storage_async_thread_naming, FileUnsharedDatabase)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
do_check_success(ss->OpenUnsharedDatabase(dbFile, 0, getter_AddRefs(conn)));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(conn);
}
TEST(storage_async_thread_naming, FileURLDatabase)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<nsIURI> uri;
do_check_success(NS_NewFileURI(getter_AddRefs(uri), dbFile));
nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
do_check_success(ss->OpenDatabaseWithFileURL(fileUrl, EmptyCString(), 0,
getter_AddRefs(conn)));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(conn);
}
TEST(storage_async_thread_naming, OverrideFileURLDatabase)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<nsIURI> uri;
do_check_success(NS_NewFileURI(getter_AddRefs(uri), dbFile));
nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
nsAutoCString override("override"_ns);
do_check_success(
ss->OpenDatabaseWithFileURL(fileUrl, override, 0, getter_AddRefs(conn)));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(override);
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(conn);
}
TEST(storage_async_thread_naming, AsyncOpenDatabase)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<mozIStorageService> ss = getService();
RefPtr<AsyncCompletionSpinner> completionSpinner =
new AsyncCompletionSpinner();
RefPtr<nsVariant> variant = new nsVariant();
variant->SetAsInterface(NS_GET_IID(nsIFile), dbFile);
do_check_success(ss->OpenAsyncDatabase(variant, 0, 0, completionSpinner));
completionSpinner->SpinUntilCompleted();
nsCOMPtr<mozIStorageConnection> conn(
do_QueryInterface(completionSpinner->mCompletionValue));
nsCOMPtr<nsIThread> target(get_conn_async_thread(conn));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(conn);
}
TEST(storage_async_thread_naming, AsyncClone)
{
HookSqliteMutex hook;
nsAutoString filename(u"test_thread_name.sqlite"_ns);
nsCOMPtr<nsIFile> dbFile;
do_check_success(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(dbFile)));
do_check_success(dbFile->Append(filename));
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
do_check_success(ss->OpenDatabase(dbFile, 0, getter_AddRefs(conn)));
RefPtr<AsyncCompletionSpinner> completionSpinner =
new AsyncCompletionSpinner();
RefPtr<nsVariant> variant = new nsVariant();
variant->SetAsInterface(NS_GET_IID(nsIFile), dbFile);
do_check_success(conn->AsyncClone(true, completionSpinner));
completionSpinner->SpinUntilCompleted();
nsCOMPtr<mozIStorageConnection> clone(
do_QueryInterface(completionSpinner->mCompletionValue));
nsCOMPtr<nsIThread> target(get_conn_async_thread(clone));
do_check_true(target);
PRThread* prThread;
target->GetPRThread(&prThread);
do_check_true(prThread);
nsAutoCString name(PR_GetThreadName(prThread));
nsAutoCString expected("sqldb:"_ns);
expected.Append(NS_ConvertUTF16toUTF8(filename));
do_check_true(StringBeginsWith(name, expected));
blocking_async_close(conn);
blocking_async_close(clone);
}

View File

@ -2,6 +2,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* PRIVACY WARNING
* ===============
*
* Database file names can be exposed through telemetry and in crash reports on
* the https://crash-stats.mozilla.org site, to allow recognizing the affected
* database.
* if your database name may contain privacy sensitive information, e.g. an
* URL origin, you should use openDatabaseWithFileURL and pass an explicit
* TelemetryFilename to it. That name will be used both for telemetry and for
* thread names in crash reports.
* If you have different needs (e.g. using the javascript module or an async
* connection from the main thread) please coordinate with the mozStorage peers.
*/
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";