зеркало из https://github.com/mozilla/gecko-dev.git
Bug 501485: Destroy plugin processes after three minutes of not being used. Timer starts when the last instance is destroyed, is canceled if a new instance is created before it fires. r=bsmedberg
This commit is contained in:
Родитель
2db6c1f414
Коммит
536e3e27dd
|
@ -340,7 +340,7 @@ static bool UnloadPluginsASAP()
|
|||
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool unloadPluginsASAP = false;
|
||||
rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
|
||||
rv = pref->GetBoolPref("dom.ipc.plugins.unloadASAP", &unloadPluginsASAP);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return unloadPluginsASAP;
|
||||
}
|
||||
|
@ -349,42 +349,6 @@ static bool UnloadPluginsASAP()
|
|||
return false;
|
||||
}
|
||||
|
||||
// helper struct for asynchronous handling of plugin unloading
|
||||
class nsPluginUnloadEvent : public nsRunnable {
|
||||
public:
|
||||
nsPluginUnloadEvent(PRLibrary* aLibrary)
|
||||
: mLibrary(aLibrary)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
PRLibrary* mLibrary;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP nsPluginUnloadEvent::Run()
|
||||
{
|
||||
if (mLibrary) {
|
||||
// put our unload call in a safety wrapper
|
||||
NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(mLibrary), nsnull);
|
||||
} else {
|
||||
NS_WARNING("missing library from nsPluginUnloadEvent");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// unload plugin asynchronously if possible, otherwise just unload now
|
||||
nsresult nsPluginHost::PostPluginUnloadEvent(PRLibrary* aLibrary)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> ev = new nsPluginUnloadEvent(aLibrary);
|
||||
if (ev && NS_SUCCEEDED(NS_DispatchToCurrentThread(ev)))
|
||||
return NS_OK;
|
||||
|
||||
// failure case
|
||||
NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(aLibrary), nsnull);
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsPluginHost::nsPluginHost()
|
||||
// No need to initialize members to nsnull, false etc because this class
|
||||
// has a zeroing operator new.
|
||||
|
@ -427,8 +391,8 @@ nsPluginHost::nsPluginHost()
|
|||
#endif
|
||||
|
||||
#ifdef MAC_CARBON_PLUGINS
|
||||
mVisiblePluginTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mHiddenPluginTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mVisiblePluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
mHiddenPluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -532,7 +496,7 @@ nsresult nsPluginHost::ReloadPlugins(bool reloadPages)
|
|||
p->mNext = nsnull;
|
||||
|
||||
// attempt to unload plugins whenever they are removed from the list
|
||||
p->TryUnloadPlugin();
|
||||
p->TryUnloadPlugin(false);
|
||||
|
||||
p = next;
|
||||
continue;
|
||||
|
@ -875,7 +839,7 @@ nsresult nsPluginHost::Destroy()
|
|||
|
||||
nsPluginTag *pluginTag;
|
||||
for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
|
||||
pluginTag->TryUnloadPlugin();
|
||||
pluginTag->TryUnloadPlugin(true);
|
||||
}
|
||||
|
||||
NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mPlugins, mNext);
|
||||
|
@ -913,8 +877,33 @@ void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
|
|||
}
|
||||
}
|
||||
|
||||
if (!hasInstance && UnloadPluginsASAP()) {
|
||||
aPluginTag->TryUnloadPlugin();
|
||||
// We have some options for unloading plugins if they have no instances.
|
||||
//
|
||||
// Unloading plugins immediately can be bad - some plugins retain state
|
||||
// between instances even when there are none. This is largely limited to
|
||||
// going from one page to another, so state is retained without an instance
|
||||
// for only a very short period of time. In order to allow this to work
|
||||
// we don't unload plugins immediately by default. This is supported
|
||||
// via a hidden user pref though.
|
||||
//
|
||||
// Another reason not to unload immediately is that loading is expensive,
|
||||
// and it is better to leave popular plugins loaded.
|
||||
//
|
||||
// Our default behavior is to try to unload a plugin three minutes after
|
||||
// its last instance is destroyed. This seems like a reasonable compromise
|
||||
// that allows us to reclaim memory while allowing short state retention
|
||||
// and avoid perf hits for loading popular plugins.
|
||||
if (!hasInstance) {
|
||||
if (UnloadPluginsASAP()) {
|
||||
aPluginTag->TryUnloadPlugin(false);
|
||||
} else {
|
||||
if (aPluginTag->mUnloadTimer) {
|
||||
aPluginTag->mUnloadTimer->Cancel();
|
||||
} else {
|
||||
aPluginTag->mUnloadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
}
|
||||
aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * 60 * 3, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,6 +1337,12 @@ nsPluginHost::TrySetUpPluginInstance(const char *aMimeType,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Cancel the plugin unload timer since we are creating
|
||||
// an instance for it.
|
||||
if (pluginTag->mUnloadTimer) {
|
||||
pluginTag->mUnloadTimer->Cancel();
|
||||
}
|
||||
|
||||
mInstances.AppendElement(instance.get());
|
||||
|
||||
#ifdef PLUGIN_LOGGING
|
||||
|
@ -2194,7 +2189,7 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
|
|||
// the library in the process then we want to attempt to unload it here.
|
||||
// Only do this if the pref is set for aggressive unloading.
|
||||
if (UnloadPluginsASAP()) {
|
||||
pluginTag->TryUnloadPlugin();
|
||||
pluginTag->TryUnloadPlugin(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2621,7 +2616,7 @@ nsPluginHost::WritePluginInfo()
|
|||
PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
|
||||
tag->mLastModifiedTime,
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
tag->mCanUnloadLibrary,
|
||||
false, // did store whether or not to unload in-process plugins
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
tag->Flags(),
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
|
@ -2885,7 +2880,6 @@ nsPluginHost::ReadPluginInfo()
|
|||
|
||||
// If this is an old plugin registry mark this plugin tag to be refreshed
|
||||
PRInt64 lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
|
||||
bool canunload = atoi(values[1]);
|
||||
PRUint32 tagflag = atoi(values[2]);
|
||||
if (!reader.NextLine())
|
||||
return rv;
|
||||
|
@ -2945,7 +2939,7 @@ nsPluginHost::ReadPluginInfo()
|
|||
(const char* const*)mimetypes,
|
||||
(const char* const*)mimedescriptions,
|
||||
(const char* const*)extensions,
|
||||
mimetypecount, lastmod, canunload, true);
|
||||
mimetypecount, lastmod, true);
|
||||
if (heapalloced)
|
||||
delete [] heapalloced;
|
||||
|
||||
|
@ -3870,6 +3864,18 @@ NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
|
|||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRefPtr<nsPluginTag> pluginTag = mPlugins;
|
||||
while (pluginTag) {
|
||||
if (pluginTag->mUnloadTimer == timer) {
|
||||
if (!IsRunningPlugin(pluginTag)) {
|
||||
pluginTag->TryUnloadPlugin(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
pluginTag = pluginTag->mNext;
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ mMimeTypes(aPluginTag->mMimeTypes),
|
|||
mMimeDescriptions(aPluginTag->mMimeDescriptions),
|
||||
mExtensions(aPluginTag->mExtensions),
|
||||
mLibrary(nsnull),
|
||||
mCanUnloadLibrary(true),
|
||||
mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
|
||||
mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
|
||||
mIsFlashPlugin(aPluginTag->mIsFlashPlugin),
|
||||
|
@ -97,11 +96,6 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
|
|||
mName(aPluginInfo->fName),
|
||||
mDescription(aPluginInfo->fDescription),
|
||||
mLibrary(nsnull),
|
||||
#ifdef XP_MACOSX
|
||||
mCanUnloadLibrary(false),
|
||||
#else
|
||||
mCanUnloadLibrary(true),
|
||||
#endif
|
||||
mIsJavaPlugin(false),
|
||||
mIsNPRuntimeEnabledJavaPlugin(false),
|
||||
mIsFlashPlugin(false),
|
||||
|
@ -190,13 +184,11 @@ nsPluginTag::nsPluginTag(const char* aName,
|
|||
const char* const* aExtensions,
|
||||
PRInt32 aVariants,
|
||||
PRInt64 aLastModifiedTime,
|
||||
bool aCanUnload,
|
||||
bool aArgsAreUTF8)
|
||||
: mPluginHost(nsnull),
|
||||
mName(aName),
|
||||
mDescription(aDescription),
|
||||
mLibrary(nsnull),
|
||||
mCanUnloadLibrary(aCanUnload),
|
||||
mIsJavaPlugin(false),
|
||||
mIsNPRuntimeEnabledJavaPlugin(false),
|
||||
mFileName(aFileName),
|
||||
|
@ -513,22 +505,16 @@ bool nsPluginTag::Equals(nsPluginTag *aPluginTag)
|
|||
return true;
|
||||
}
|
||||
|
||||
void nsPluginTag::TryUnloadPlugin()
|
||||
void nsPluginTag::TryUnloadPlugin(bool inShutdown)
|
||||
{
|
||||
// We never want to send NPP_Shutdown to an in-process plugin unless
|
||||
// this process is shutting down.
|
||||
if (mLibrary && !inShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEntryPoint) {
|
||||
mEntryPoint->Shutdown();
|
||||
mEntryPoint = nsnull;
|
||||
}
|
||||
|
||||
// before we unload check if we are allowed to, see bug #61388
|
||||
if (mLibrary && mCanUnloadLibrary) {
|
||||
// unload the plugin asynchronously by posting a PLEvent
|
||||
nsPluginHost::PostPluginUnloadEvent(mLibrary);
|
||||
}
|
||||
|
||||
// we should zero it anyway, it is going to be unloaded by
|
||||
// CleanUnsedLibraries before we need to call the library
|
||||
// again so the calling code should not be fooled and reload
|
||||
// the library fresh
|
||||
mLibrary = nsnull;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIPluginTag.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
class nsPluginHost;
|
||||
struct PRLibrary;
|
||||
|
@ -85,12 +86,11 @@ public:
|
|||
const char* const* aExtensions,
|
||||
PRInt32 aVariants,
|
||||
PRInt64 aLastModifiedTime = 0,
|
||||
bool aCanUnload = true,
|
||||
bool aArgsAreUTF8 = false);
|
||||
virtual ~nsPluginTag();
|
||||
|
||||
void SetHost(nsPluginHost * aHost);
|
||||
void TryUnloadPlugin();
|
||||
void TryUnloadPlugin(bool inShutdown);
|
||||
void Mark(PRUint32 mask);
|
||||
void UnMark(PRUint32 mask);
|
||||
bool HasFlag(PRUint32 flag);
|
||||
|
@ -109,7 +109,6 @@ public:
|
|||
nsTArray<nsCString> mExtensions; // UTF-8
|
||||
PRLibrary *mLibrary;
|
||||
nsRefPtr<nsNPAPIPlugin> mEntryPoint;
|
||||
bool mCanUnloadLibrary;
|
||||
bool mIsJavaPlugin;
|
||||
bool mIsNPRuntimeEnabledJavaPlugin;
|
||||
bool mIsFlashPlugin;
|
||||
|
@ -117,6 +116,7 @@ public:
|
|||
nsCString mFullPath; // UTF-8
|
||||
nsCString mVersion; // UTF-8
|
||||
PRInt64 mLastModifiedTime;
|
||||
nsCOMPtr<nsITimer> mUnloadTimer;
|
||||
private:
|
||||
PRUint32 mFlags;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче