Bug 1545123 - simplify how we get directory information for plugins, r=handyman,mconley

In this change we:
- stop treating the nsPluginDirServiceProvider as a directory provider, as its
  GetFile implementation was a no-op anyway - registering it didn't make any
  difference.
- stop treating it as a class entirely, because the PLID getters were already
  static, so instantiating it also didn't do anything.
- move IO from the plugin directory list provider and the Windows-only PLID
  getters into nsPluginHost. This enables us to move it off of the main thread
  later - the directory getting has to happen on the main thread, but we can
  postpone further checks on the nsIFile instances.
- in the process, stop doing exists() calls on files because we can fail more
  lazily. This allows us to remove more allowlist entries from
  browser_startup_mainthreadio, though the `isDirectory` calls will actually
  still cause IO - they don't seem to create IO markers in the profiler.
  We will move this IO away from the main thread in subsequent commits.

Depends on D48328

Differential Revision: https://phabricator.services.mozilla.com/D48329

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gijs Kruitbosch 2019-11-02 22:33:42 +00:00
Родитель abcf21a78b
Коммит 608f3e7539
6 изменённых файлов: 119 добавлений и 250 удалений

Просмотреть файл

@ -332,12 +332,6 @@ const startupPhases = {
// We reach this phase right after showing the first browser window.
// This means that any I/O at this point delayed first paint.
"before first paint": [
{
// bug 1541226
path: "ProfD:",
condition: WIN,
stat: 1,
},
{
// bug 1545119
path: "OldUpdRootD:",
@ -369,12 +363,6 @@ const startupPhases = {
condition: WIN,
stat: 1,
},
{
// bug 1545123
path: "UserPlugins:",
condition: WIN,
stat: 1,
},
{
// bug 1545123
path: "ProfD:plugins/nptest.dll",

Просмотреть файл

@ -7,59 +7,21 @@
#include "nsCRT.h"
#include "nsIFile.h"
#include "nsDependentString.h"
#include "nsArrayEnumerator.h"
#include "mozilla/Preferences.h"
#include <windows.h>
#include "nsIWindowsRegKey.h"
using namespace mozilla;
//*****************************************************************************
// nsPluginDirServiceProvider::Constructor/Destructor
//*****************************************************************************
nsPluginDirServiceProvider::nsPluginDirServiceProvider() {}
nsPluginDirServiceProvider::~nsPluginDirServiceProvider() {}
//*****************************************************************************
// nsPluginDirServiceProvider::nsISupports
//*****************************************************************************
NS_IMPL_ISUPPORTS(nsPluginDirServiceProvider, nsIDirectoryServiceProvider)
//*****************************************************************************
// nsPluginDirServiceProvider::nsIDirectoryServiceProvider
//*****************************************************************************
NS_IMETHODIMP
nsPluginDirServiceProvider::GetFile(const char* charProp, bool* persistant,
nsIFile** _retval) {
NS_ENSURE_ARG(charProp);
*_retval = nullptr;
*persistant = false;
return NS_ERROR_FAILURE;
/* static */ nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
aDirs);
return NS_OK;
}
nsresult nsPluginDirServiceProvider::GetPLIDDirectories(
nsISimpleEnumerator** aEnumerator) {
NS_ENSURE_ARG_POINTER(aEnumerator);
*aEnumerator = nullptr;
nsCOMArray<nsIFile> dirs;
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, dirs);
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, dirs);
return NS_NewArrayEnumerator(aEnumerator, dirs, NS_GET_IID(nsIFile));
}
nsresult nsPluginDirServiceProvider::GetPLIDDirectoriesWithRootKey(
uint32_t aKey, nsCOMArray<nsIFile>& aDirs) {
/* static */ nsresult GetPLIDDirectoriesWithRootKey(
uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE);
@ -85,37 +47,14 @@ nsresult nsPluginDirServiceProvider::GetPLIDDirectoriesWithRootKey(
nsAutoString path;
rv = childKey->ReadStringValue(NS_LITERAL_STRING("Path"), path);
if (NS_SUCCEEDED(rv)) {
// We deliberately do not do any further checks here on whether
// these are actually directories, whether they even exist, or
// whether they are duplicates. The pluginhost code will do them.
// This allows the whole process to avoid mainthread IO.
nsCOMPtr<nsIFile> localFile;
if (NS_SUCCEEDED(
NS_NewLocalFile(path, true, getter_AddRefs(localFile))) &&
localFile) {
// Some vendors use a path directly to the DLL so chop off
// the filename
bool isDir = false;
if (NS_SUCCEEDED(localFile->IsDirectory(&isDir)) && !isDir) {
nsCOMPtr<nsIFile> temp;
localFile->GetParent(getter_AddRefs(temp));
if (temp) localFile = temp;
}
// Now we check to make sure it's actually on disk and
// To see if we already have this directory in the array
bool isFileThere = false;
bool isDupEntry = false;
if (NS_SUCCEEDED(localFile->Exists(&isFileThere)) && isFileThere) {
int32_t c = aDirs.Count();
for (int32_t i = 0; i < c; i++) {
nsIFile* dup = static_cast<nsIFile*>(aDirs[i]);
if (dup && NS_SUCCEEDED(dup->Equals(localFile, &isDupEntry)) &&
isDupEntry) {
break;
}
}
if (!isDupEntry) {
aDirs.AppendObject(localFile);
}
}
rv = NS_NewLocalFile(path, true, getter_AddRefs(localFile));
if (NS_SUCCEEDED(rv) && localFile) {
aDirs.AppendElement(localFile);
}
}
}

Просмотреть файл

@ -6,35 +6,14 @@
#ifndef nsPluginDirServiceProvider_h_
#define nsPluginDirServiceProvider_h_
#include "nsIDirectoryService.h"
#if defined(XP_WIN)
# include "nsCOMArray.h"
#endif
class nsISimpleEnumerator;
//*****************************************************************************
// class nsPluginDirServiceProvider
//*****************************************************************************
class nsPluginDirServiceProvider : public nsIDirectoryServiceProvider {
public:
nsPluginDirServiceProvider();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDIRECTORYSERVICEPROVIDER
#ifdef XP_WIN
static nsresult GetPLIDDirectories(nsISimpleEnumerator** aEnumerator);
# include "nsCOMPtr.h"
# include "nsTArray.h"
private:
static nsresult GetPLIDDirectoriesWithRootKey(uint32_t aKey,
nsCOMArray<nsIFile>& aDirs);
#endif
static nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
protected:
virtual ~nsPluginDirServiceProvider();
};
static nsresult GetPLIDDirectoriesWithRootKey(
uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs);
#endif // XP_WIN
#endif // nsPluginDirServiceProvider_h_

Просмотреть файл

@ -99,6 +99,8 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/ResultExtensions.h"
#if defined(XP_WIN)
# include "nsIWindowMediator.h"
# include "nsIBaseWindow.h"
@ -145,9 +147,6 @@ static const uint32_t kDefaultPluginUnloadingTimeout = 30;
static const char* kPluginRegistryVersion = "0.19";
static const char kDirectoryServiceContractID[] =
"@mozilla.org/file/directory_service;1";
#define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
LazyLogModule nsPluginLogging::gNPNLog(NPN_LOG_NAME);
@ -837,15 +836,6 @@ nsresult nsPluginHost::UnloadPlugins() {
NS_RELEASE(sPluginTempDir);
}
#ifdef XP_WIN
if (mPrivateDirServiceProvider) {
nsCOMPtr<nsIDirectoryService> dirService =
do_GetService(kDirectoryServiceContractID);
if (dirService) dirService->UnregisterProvider(mPrivateDirServiceProvider);
mPrivateDirServiceProvider = nullptr;
}
#endif /* XP_WIN */
mPluginsLoaded = false;
return NS_OK;
@ -2280,31 +2270,6 @@ void nsPluginHost::UpdatePluginBlocklistState(nsPluginTag* aPluginTag,
}
}
nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator* dirEnum,
bool aCreatePluginList,
bool* aPluginsChanged) {
MOZ_ASSERT(XRE_IsParentProcess());
bool hasMore;
while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv)) continue;
nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv)) continue;
// don't pass aPluginsChanged directly to prevent it from been reset
bool pluginschanged = false;
ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
if (pluginschanged) *aPluginsChanged = true;
// if changes are detected and we are not creating the list, do not proceed
if (!aCreatePluginList && *aPluginsChanged) break;
}
return NS_OK;
}
void nsPluginHost::IncrementChromeEpoch() {
MOZ_ASSERT(XRE_IsParentProcess());
mPluginEpoch++;
@ -2465,88 +2430,63 @@ nsresult nsPluginHost::FindPlugins(bool aCreatePluginList,
*aPluginsChanged = false;
nsresult rv;
nsresult rv = EnsurePluginReg();
if (NS_FAILED(rv)) {
// If the profile isn't yet available then don't scan for plugins
return rv == NS_ERROR_NOT_AVAILABLE ? NS_OK : rv;
}
// Read cached plugins info. If the profile isn't yet available then don't
// scan for plugins
if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE) return NS_OK;
// Read cached plugins info.
ReadPluginInfo();
#ifdef XP_WIN
// Failure here is not a show-stopper so just warn.
rv = EnsurePrivateDirServiceProvider();
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
#endif /* XP_WIN */
// Scan plugin directories:
nsTArray<nsCOMPtr<nsIFile>> pluginDirs;
MOZ_TRY(DeterminePluginDirs(pluginDirs));
nsCOMPtr<nsIProperties> dirService(
do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> dirList;
// Scan plugins directories;
// don't pass aPluginsChanged directly, to prevent its
// possible reset in subsequent ScanPluginsDirectory calls
bool pluginschanged = false;
// Scan the app-defined list of plugin dirs.
rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
getter_AddRefs(dirList));
if (NS_SUCCEEDED(rv)) {
ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
if (pluginschanged) *aPluginsChanged = true;
// In tests, load plugins from the profile.
if (xpc::IsInAutomation()) {
nsCOMPtr<nsIFile> profDir;
rv = dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
getter_AddRefs(profDir));
if (NS_SUCCEEDED(rv)) {
profDir->Append(NS_LITERAL_STRING("plugins"));
ScanPluginsDirectory(profDir, aCreatePluginList, &pluginschanged);
if (pluginschanged) {
*aPluginsChanged = true;
}
for (nsIFile* pluginDir : pluginDirs) {
if (!pluginDir) {
continue;
}
// Ensure we have a directory; if this isn't a directory, try the parent.
// We do this because in some cases items in this list of supposed plugin
// directories can be individual plugin files instead of directories.
bool isDir = false;
nsCOMPtr<nsIFile> parent;
if (NS_FAILED(pluginDir->IsDirectory(&isDir)) || !isDir) {
pluginDir->GetParent(getter_AddRefs(parent));
pluginDir = parent;
if (!pluginDir) {
continue;
}
}
// pluginDir not existing will be handled transparently in
// ScanPluginsDirectory
// if we are just looking for possible changes,
// no need to proceed if changes are detected
if (!aCreatePluginList && *aPluginsChanged) {
NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins,
mNext);
return NS_OK;
// don't pass aPluginsChanged directly, to prevent its
// possible reset in subsequent ScanPluginsDirectory calls
bool pluginschanged = false;
ScanPluginsDirectory(pluginDir, aCreatePluginList, &pluginschanged);
if (pluginschanged) {
*aPluginsChanged = true;
if (!aCreatePluginList) {
// We're just looking for changes, so we can stop looking.
break;
}
}
}
// if we are just looking for possible changes,
// no need to proceed if changes are detected
if (!aCreatePluginList && *aPluginsChanged) {
NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
return NS_OK;
}
mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
// the rest is optional
#ifdef XP_WIN
bool bScanPLIDs = Preferences::GetBool("plugin.scan.plid.all", false);
// Now lets scan any PLID directories
if (bScanPLIDs && mPrivateDirServiceProvider) {
rv =
mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
if (NS_SUCCEEDED(rv)) {
ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
if (pluginschanged) *aPluginsChanged = true;
// if we are just looking for possible changes,
// no need to proceed if changes are detected
if (!aCreatePluginList && *aPluginsChanged) {
NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins,
mNext);
return NS_OK;
}
}
}
#endif
// We should also consider plugins to have changed if any plugins have been
// removed. We'll know if any were removed if they weren't taken out of the
// cached plugins list during our scan, thus we can assume something was
@ -2882,7 +2822,6 @@ nsresult nsPluginHost::EnsurePluginReg() {
}
nsresult rv;
nsCOMPtr<nsIProperties> directoryService(
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
@ -2905,6 +2844,55 @@ nsresult nsPluginHost::EnsurePluginReg() {
return mPluginRegFile->AppendNative(kPluginRegistryFilename);
}
nsresult nsPluginHost::DeterminePluginDirs(
nsTArray<nsCOMPtr<nsIFile>>& pluginDirs) {
nsresult rv;
nsCOMPtr<nsIProperties> dirService(
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
// Get the app-defined list of plugin dirs.
nsCOMPtr<nsISimpleEnumerator> dirEnum;
MOZ_TRY(dirService->Get(NS_APP_PLUGINS_DIR_LIST,
NS_GET_IID(nsISimpleEnumerator),
getter_AddRefs(dirEnum)));
bool hasMore = false;
while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
if (NS_SUCCEEDED(rv)) {
pluginDirs.AppendElement(nextDir);
}
}
}
// In tests, load plugins from the profile.
if (xpc::IsInAutomation()) {
nsCOMPtr<nsIFile> profDir;
rv = dirService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
getter_AddRefs(profDir));
if (NS_SUCCEEDED(rv)) {
profDir->Append(NS_LITERAL_STRING("plugins"));
pluginDirs.AppendElement(profDir);
}
}
// Get the directories from the windows registry. Note: these can
// be files instead of directories. We'll have to filter them later.
#ifdef XP_WIN
bool bScanPLIDs = Preferences::GetBool("plugin.scan.plid.all", false);
if (bScanPLIDs) {
GetPLIDDirectories(pluginDirs);
}
#endif /* XP_WIN */
return NS_OK;
}
nsresult nsPluginHost::ReadPluginInfo() {
MOZ_ASSERT(XRE_IsParentProcess());
@ -3160,21 +3148,6 @@ void nsPluginHost::RemoveCachedPluginsInfo(const char* filePath,
}
}
#ifdef XP_WIN
nsresult nsPluginHost::EnsurePrivateDirServiceProvider() {
if (!mPrivateDirServiceProvider) {
nsresult rv;
mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
nsCOMPtr<nsIDirectoryService> dirService(
do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv)) return rv;
rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
#endif /* XP_WIN */
nsresult nsPluginHost::NewPluginURLStream(
const nsString& aURL, nsNPAPIPluginInstance* aInstance,
nsNPAPIPluginStreamListener* aListener, nsIInputStream* aPostStream,

Просмотреть файл

@ -310,16 +310,14 @@ class nsPluginHost final : public nsIPluginHost,
nsresult ScanPluginsDirectory(nsIFile* pluginsDir, bool aCreatePluginList,
bool* aPluginsChanged);
nsresult ScanPluginsDirectoryList(nsISimpleEnumerator* dirEnum,
bool aCreatePluginList,
bool* aPluginsChanged);
nsresult EnsurePluginLoaded(nsPluginTag* aPluginTag);
bool IsRunningPlugin(nsPluginTag* aPluginTag);
nsresult EnsurePluginReg();
nsresult DeterminePluginDirs(nsTArray<nsCOMPtr<nsIFile>>& pluginDirs);
// Read plugin info (either from prefs or disk)
nsresult ReadPluginInfo();
@ -346,8 +344,6 @@ class nsPluginHost final : public nsIPluginHost,
// Returns the first plugin at |path|
nsPluginTag* FirstPluginWithPath(const nsCString& path);
nsresult EnsurePrivateDirServiceProvider();
void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
// To be used by the chrome process whenever the set of plugins changes.
@ -390,8 +386,6 @@ class nsPluginHost final : public nsIPluginHost,
// An nsIFile for the pluginreg.dat file in the profile.
nsCOMPtr<nsIFile> mPluginRegFile;
#ifdef XP_WIN
RefPtr<nsPluginDirServiceProvider> mPrivateDirServiceProvider;
// In order to reload plugins when they change, we watch the registry via
// this object.
nsCOMPtr<nsIWindowsRegKey> mRegKeyHKLM;

Просмотреть файл

@ -370,11 +370,7 @@ class nsAppDirectoryEnumerator : public nsSimpleEnumerator {
nsCOMPtr<nsIFile> testFile;
(void)mProvider->GetFile(*mCurrentKey++, &dontCare,
getter_AddRefs(testFile));
// Don't return a file which does not exist.
bool exists;
if (testFile && NS_SUCCEEDED(testFile->Exists(&exists)) && exists) {
mNext = testFile;
}
mNext = testFile;
}
*aResult = mNext != nullptr;
return NS_OK;