Bug 1707963: Let the PermissionManager be initialized lazily but not after shutdown started. r=permissions-reviewers,timhuang,janv

Differential Revision: https://phabricator.services.mozilla.com/D132088
This commit is contained in:
Jens Stutte 2021-12-08 22:10:18 +00:00
parent 0d99e5e9f8
commit c05fc0f8b4
6 changed files with 37 additions and 51 deletions

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/AbstractThread.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/ContentPrincipal.h"
@ -612,12 +613,6 @@ PermissionManager::PermissionKey::CreateFromURI(nsIURI* aURI,
return new PermissionKey(origin);
}
/* static */
void PermissionManager::Startup() {
nsCOMPtr<nsIPermissionManager> permManager =
do_GetService("@mozilla.org/permissionmanager;1");
}
////////////////////////////////////////////////////////////////////////////////
// PermissionManager Implementation
@ -628,7 +623,6 @@ PermissionManager::PermissionManager()
: mMonitor("PermissionManager::mMonitor"),
mState(eInitializing),
mMemoryOnlyDB(false),
mBlockerAdded(false),
mLargestID(0) {}
PermissionManager::~PermissionManager() {
@ -679,6 +673,12 @@ PermissionManager* PermissionManager::GetInstance() {
}
nsresult PermissionManager::Init() {
// If we are already shutting down, do not permit a creation.
// This must match the phase in GetAsyncShutdownClient.
if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
// If the 'permissions.memory_only' pref is set to true, then don't write any
// permission settings to disk, but keep them in a memory-only database.
mMemoryOnlyDB = Preferences::GetBool("permissions.memory_only", false);
@ -705,31 +705,22 @@ nsresult PermissionManager::Init() {
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "profile-before-change", true);
observerService->AddObserver(this, "profile-do-change", true);
observerService->AddObserver(this, "testonly-reload-permissions-from-disk",
true);
}
if (XRE_IsParentProcess()) {
nsCOMPtr<nsIAsyncShutdownClient> asc = GetShutdownPhase();
if (asc) {
nsAutoString blockerName;
MOZ_ALWAYS_SUCCEEDS(GetName(blockerName));
// This method can fail during some xpcshell-tests.
nsresult rv =
asc->AddBlocker(this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__),
__LINE__, blockerName);
Unused << NS_WARN_IF(NS_FAILED(rv));
if (NS_SUCCEEDED(rv)) {
mBlockerAdded = true;
}
nsCOMPtr<nsIAsyncShutdownClient> asc = GetAsyncShutdownClient();
if (!asc) {
return NS_ERROR_NOT_AVAILABLE;
}
nsAutoString blockerName;
MOZ_ALWAYS_SUCCEEDS(GetName(blockerName));
if (!mBlockerAdded) {
ClearOnShutdown(&gPermissionManager);
}
nsresult rv = asc->AddBlocker(
this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, blockerName);
NS_ENSURE_SUCCESS(rv, rv);
}
AddIdleDailyMaintenanceJob();
@ -2556,15 +2547,7 @@ NS_IMETHODIMP PermissionManager::Observe(nsISupports* aSubject,
const char16_t* someData) {
ENSURE_NOT_CHILD_PROCESS;
if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
if (!mBlockerAdded) {
// The profile is about to change and the shutdown blocker has not been
// added yet (we are probably in a xpcshell-test).
RemoveIdleDailyMaintenanceJob();
RemoveAllFromMemory();
CloseDB(eNone);
}
} else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
// the profile has already changed; init the db from the new location
InitDB(false);
} else if (!nsCRT::strcmp(aTopic, "testonly-reload-permissions-from-disk")) {
@ -3827,7 +3810,7 @@ nsresult PermissionManager::TestPermissionWithoutDefaultsFromPrincipal(
void PermissionManager::MaybeCompleteShutdown() {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIAsyncShutdownClient> asc = GetShutdownPhase();
nsCOMPtr<nsIAsyncShutdownClient> asc = GetAsyncShutdownClient();
MOZ_ASSERT(asc);
DebugOnly<nsresult> rv = asc->RemoveBlocker(this);
@ -3866,7 +3849,8 @@ PermissionManager::GetState(nsIPropertyBag** aBagOut) {
return NS_OK;
}
nsCOMPtr<nsIAsyncShutdownClient> PermissionManager::GetShutdownPhase() const {
nsCOMPtr<nsIAsyncShutdownClient> PermissionManager::GetAsyncShutdownClient()
const {
nsresult rv;
nsCOMPtr<nsIAsyncShutdownService> svc =
do_GetService("@mozilla.org/async-shutdown-service;1", &rv);
@ -3875,7 +3859,9 @@ nsCOMPtr<nsIAsyncShutdownClient> PermissionManager::GetShutdownPhase() const {
}
nsCOMPtr<nsIAsyncShutdownClient> client;
rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
// This feels very late but there seem to be other services that rely on
// us later than "profile-before-change".
rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return client;

View File

@ -194,15 +194,6 @@ class PermissionManager final : public nsIPermissionManager,
nsIURI* aURI, const OriginAttributes* aOriginAttributes,
const nsACString& aType, uint32_t* aPermission);
/**
* Initialize the permission-manager service.
* The permission manager is always initialized at startup because when it
* was lazy-initialized on demand, it was possible for it to be created
* once shutdown had begun, resulting in the manager failing to correctly
* shutdown because it missed its shutdown observer notification.
*/
static void Startup();
nsresult RemovePermissionsWithAttributes(OriginAttributesPattern& aAttrs);
/**
@ -529,7 +520,7 @@ class PermissionManager final : public nsIPermissionManager,
uint32_t aExpireType, int64_t aExpireTime,
int64_t aModificationTime, int64_t aId);
nsCOMPtr<nsIAsyncShutdownClient> GetShutdownPhase() const;
nsCOMPtr<nsIAsyncShutdownClient> GetAsyncShutdownClient() const;
void MaybeCompleteShutdown();
@ -646,8 +637,6 @@ class PermissionManager final : public nsIPermissionManager,
bool mMemoryOnlyDB;
bool mBlockerAdded;
nsTHashtable<PermissionHashKey> mPermissionTable;
// a unique, monotonically increasing id used to identify each database entry
int64_t mLargestID;

View File

@ -58,6 +58,11 @@ add_task(function test() {
Assert.ok(true, "There wasn't a nsINavHistoryService");
}
// We need to execute a pm method to be sure that the DB is fully
// initialized.
var pm = Services.perms;
Assert.ok(pm.all.length >= 0, "Permission manager not initialized?");
let db = Services.storage.openDatabase(GetPermissionsFile(profile));
db.schemaVersion = 4;
db.executeSimpleSQL("DROP TABLE moz_perms");

View File

@ -243,8 +243,6 @@ nsresult nsLayoutStatics::Initialize() {
ProcessPriorityManager::Init();
PermissionManager::Startup();
UIDirectionManager::Initialize();
CacheObserver::Init();

View File

@ -100,6 +100,13 @@ add_task(async function test_hawk_authenticated_request() {
let timeOffset = -1 * clockSkew;
let localTime = then + clockSkew;
// XXX: This test fails if run with socket process enabled. It passes if
// we force the permission manager to be initialized, but this might just
// trigger some side effect and seems not a clean solution so we disabled
// the entire test, see bug 1743079.
// var pm = Services.perms;
// Assert.ok(pm.all.length >= 0, "Permission manager not initialized?");
// Set the accept-languages pref to the Nepalese dialect of Zulu.
let acceptLanguage = "zu-NP"; // omit trailing ';', which our HTTP libs snip
Services.prefs.setStringPref("intl.accept_languages", acceptLanguage);

View File

@ -33,7 +33,8 @@ tags = remote-settings blocklist
[test_hawkclient.js]
skip-if = os == "android"
[test_hawkrequest.js]
skip-if = os == "android"
skip-if = os == "android" || socketprocess_networking
# See bug 1743079 for socket process.
[test_logmanager.js]
[test_observers.js]