Bug 1194488: Whitelist specific plugins for async init; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Mon, 31 Aug 2015 17:04:25 -0600
changeset 260948 a7d95d113ad69cb52ade4563f92be4cf176e3134
parent 260947 e56d85b82ec77c103a5ca0d0477ebbfddf4a9e00
child 260949 24cd0974b365f1eebd22167e5c004d00305e86a5
push id64635
push useraklotz@mozilla.com
push dateFri, 04 Sep 2015 20:05:21 +0000
treeherdermozilla-inbound@a7d95d113ad6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1194488
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1194488: Whitelist specific plugins for async init; r=jimm
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsPluginTags.cpp
dom/plugins/base/nsPluginTags.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -262,17 +262,17 @@ nsNPAPIPlugin::RunPluginOOP(const nsPlug
 inline PluginLibrary*
 GetNewPluginLibrary(nsPluginTag *aPluginTag)
 {
   if (!aPluginTag) {
     return nullptr;
   }
 
   if (XRE_IsContentProcess()) {
-    return PluginModuleContentParent::LoadModule(aPluginTag->mId);
+    return PluginModuleContentParent::LoadModule(aPluginTag->mId, aPluginTag);
   }
 
   if (nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
     return PluginModuleChromeParent::LoadModule(aPluginTag->mFullPath.get(), aPluginTag->mId, aPluginTag);
   }
   return new PluginPRLibrary(aPluginTag->mFullPath.get(), aPluginTag->mLibrary);
 }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -262,16 +262,17 @@ nsPluginTag::nsPluginTag(const char* aNa
                          bool fromExtension,
                          bool aArgsAreUTF8)
   : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion),
     mId(sNextId++),
     mContentProcessRunningCount(0),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
+    mSupportsAsyncInit(false),
     mFullPath(aFullPath),
     mLastModifiedTime(aLastModifiedTime),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
     mCachedBlocklistStateValid(false),
     mIsFromExtension(fromExtension)
 {
   InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
            static_cast<uint32_t>(aVariants));
@@ -338,22 +339,32 @@ void nsPluginTag::InitMime(const char* c
     if (!nsPluginHost::IsTypeWhitelisted(mimeType.get())) {
       continue;
     }
 
     // Look for certain special plugins.
     switch (nsPluginHost::GetSpecialType(mimeType)) {
       case nsPluginHost::eSpecialType_Java:
         mIsJavaPlugin = true;
+        mSupportsAsyncInit = true;
         break;
       case nsPluginHost::eSpecialType_Flash:
         mIsFlashPlugin = true;
+        mSupportsAsyncInit = true;
+        break;
+      case nsPluginHost::eSpecialType_Silverlight:
+      case nsPluginHost::eSpecialType_Unity:
+        mSupportsAsyncInit = true;
         break;
       case nsPluginHost::eSpecialType_None:
       default:
+#ifndef RELEASE_BUILD
+        // Allow async init for all plugins on Nightly and Aurora
+        mSupportsAsyncInit = true;
+#endif
         break;
     }
 
     // Fill in our MIME type array.
     mMimeTypes.AppendElement(mimeType);
 
     // Now fill in the MIME descriptions.
     if (aMimeDescriptions && aMimeDescriptions[i]) {
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -160,16 +160,17 @@ public:
 
   // True if we've ever created an instance of this plugin in the current process.
   bool          mHadLocalInstance;
 
   PRLibrary     *mLibrary;
   nsRefPtr<nsNPAPIPlugin> mPlugin;
   bool          mIsJavaPlugin;
   bool          mIsFlashPlugin;
+  bool          mSupportsAsyncInit;
   nsCString     mFullPath; // UTF-8
   int64_t       mLastModifiedTime;
   nsCOMPtr<nsITimer> mUnloadTimer;
 
   void          InvalidateBlocklistState();
 
 private:
   virtual ~nsPluginTag();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -202,18 +202,19 @@ namespace {
 /**
  * Objects of this class remain linked until either an error occurs in the
  * plugin initialization sequence, or until
  * PluginModuleContentParent::OnLoadPluginResult has completed executing.
  */
 class PluginModuleMapping : public PRCList
 {
 public:
-    explicit PluginModuleMapping(uint32_t aPluginId)
+    explicit PluginModuleMapping(uint32_t aPluginId, bool aAllowAsyncInit)
         : mPluginId(aPluginId)
+        , mAllowAsyncInit(aAllowAsyncInit)
         , mProcessIdValid(false)
         , mModule(nullptr)
         , mChannelOpened(false)
     {
         MOZ_COUNT_CTOR(PluginModuleMapping);
         PR_INIT_CLIST(this);
         PR_APPEND_LINK(this, &sModuleListHead);
     }
@@ -235,17 +236,17 @@ public:
     {
         mChannelOpened = true;
     }
 
     PluginModuleContentParent*
     GetModule()
     {
         if (!mModule) {
-            mModule = new PluginModuleContentParent();
+            mModule = new PluginModuleContentParent(mAllowAsyncInit);
         }
         return mModule;
     }
 
     static PluginModuleMapping*
     AssociateWithProcessId(uint32_t aPluginId, base::ProcessId aProcessId)
     {
         PluginModuleMapping* mapping =
@@ -328,16 +329,17 @@ private:
     AssociateWithProcessId(base::ProcessId aProcessId)
     {
         MOZ_ASSERT(!mProcessIdValid);
         mProcessId = aProcessId;
         mProcessIdValid = true;
     }
 
     uint32_t mPluginId;
+    bool mAllowAsyncInit;
     bool mProcessIdValid;
     base::ProcessId mProcessId;
     PluginModuleContentParent* mModule;
     bool mChannelOpened;
 
     friend class NotifyLoadingModule;
 
     static PRCList sModuleListHead;
@@ -367,20 +369,22 @@ mozilla::plugins::TerminatePlugin(uint32
     PluginModuleChromeParent* chromeParent =
         static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
     chromeParent->TerminateChildProcess(MessageLoop::current(),
                                         aMonitorDescription,
                                         aBrowserDumpId);
 }
 
 /* static */ PluginLibrary*
-PluginModuleContentParent::LoadModule(uint32_t aPluginId)
+PluginModuleContentParent::LoadModule(uint32_t aPluginId,
+                                      nsPluginTag* aPluginTag)
 {
     PluginModuleMapping::NotifyLoadingModule loadingModule;
-    nsAutoPtr<PluginModuleMapping> mapping(new PluginModuleMapping(aPluginId));
+    nsAutoPtr<PluginModuleMapping> mapping(
+            new PluginModuleMapping(aPluginId, aPluginTag->mSupportsAsyncInit));
 
     MOZ_ASSERT(XRE_IsContentProcess());
 
     /*
      * We send a LoadPlugin message to the chrome process using an intr
      * message. Before it sends its response, it sends a message to create
      * PluginModuleParent instance. That message is handled by
      * PluginModuleContentParent::Initialize, which saves the instance in
@@ -498,18 +502,19 @@ PluginModuleChromeParent::LoadModule(con
     // set. This should be changed if the firefox.js pref file is changed.
     if (aPluginTag->mIsFlashPlugin &&
         !PR_GetEnv("MOZ_ALLOW_WEAKER_SANDBOX") && sandboxLevel < 2) {
         sandboxLevel = 2;
     }
 #endif
 #endif
 
-    nsAutoPtr<PluginModuleChromeParent> parent(new PluginModuleChromeParent(aFilePath, aPluginId,
-                                                                            sandboxLevel));
+    nsAutoPtr<PluginModuleChromeParent> parent(
+            new PluginModuleChromeParent(aFilePath, aPluginId, sandboxLevel,
+                                         aPluginTag->mSupportsAsyncInit));
     UniquePtr<LaunchCompleteTask> onLaunchedRunnable(new LaunchedTask(parent));
     parent->mSubprocess->SetCallRunnableImmediately(!parent->mIsStartingAsync);
     TimeStamp launchStart = TimeStamp::Now();
     bool launched = parent->mSubprocess->Launch(Move(onLaunchedRunnable),
                                                 sandboxLevel);
     if (!launched) {
         // We never reached open
         parent->mShutdown = true;
@@ -630,17 +635,17 @@ PluginModuleChromeParent::WaitForIPCConn
     MOZ_ASSERT(process);
     process->SetCallRunnableImmediately(true);
     if (!process->WaitUntilConnected()) {
         return false;
     }
     return true;
 }
 
-PluginModuleParent::PluginModuleParent(bool aIsChrome)
+PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit)
     : mQuirks(QUIRKS_NOT_INITIALIZED)
     , mIsChrome(aIsChrome)
     , mShutdown(false)
     , mHadLocalInstance(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
     , mNPPIface(nullptr)
@@ -648,17 +653,18 @@ PluginModuleParent::PluginModuleParent(b
     , mTaskFactory(this)
     , mIsFlashPlugin(false)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
     , mIsNPShutdownPending(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
-    mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
+    mIsStartingAsync = aAllowAsyncInit &&
+                       Preferences::GetBool(kAsyncInitPref, false);
 #if defined(MOZ_CRASHREPORTER)
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
                                        mIsStartingAsync ?
                                            NS_LITERAL_CSTRING("1") :
                                            NS_LITERAL_CSTRING("0"));
 #endif
 #endif
 }
@@ -671,33 +677,34 @@ PluginModuleParent::~PluginModuleParent(
 
     if (!mShutdown) {
         NS_WARNING("Plugin host deleted the module without shutting down.");
         NPError err;
         NP_Shutdown(&err);
     }
 }
 
-PluginModuleContentParent::PluginModuleContentParent()
-    : PluginModuleParent(false)
+PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit)
+    : PluginModuleParent(false, aAllowAsyncInit)
 {
     Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 PluginModuleContentParent::~PluginModuleContentParent()
 {
     Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 bool PluginModuleChromeParent::sInstantiated = false;
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
                                                    uint32_t aPluginId,
-                                                   int32_t aSandboxLevel)
-    : PluginModuleParent(true)
+                                                   int32_t aSandboxLevel,
+                                                   bool aAllowAsyncInit)
+    : PluginModuleParent(true, aAllowAsyncInit)
     , mSubprocess(new PluginProcessParent(aFilePath))
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
     , mHangAnnotatorMutex("PluginModuleChromeParent::mHangAnnotatorMutex")
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -92,17 +92,17 @@ protected:
                                const InfallibleTArray<nsCString>& aNames,
                                const InfallibleTArray<nsCString>& aValues)
                                override;
 
     virtual bool
     DeallocPPluginInstanceParent(PPluginInstanceParent* aActor) override;
 
 public:
-    explicit PluginModuleParent(bool aIsChrome);
+    explicit PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit);
     virtual ~PluginModuleParent();
 
     bool RemovePendingSurrogate(const nsRefPtr<PluginAsyncSurrogate>& aSurrogate);
 
     /** @return the state of the pref that controls async plugin init */
     bool IsStartingAsync() const { return mIsStartingAsync; }
     /** @return whether this modules NP_Initialize has successfully completed
         executing */
@@ -339,19 +339,19 @@ protected:
     nsTArray<nsRefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
     nsresult          mAsyncNewRv;
     uint32_t          mRunID;
 };
 
 class PluginModuleContentParent : public PluginModuleParent
 {
   public:
-    explicit PluginModuleContentParent();
+    explicit PluginModuleContentParent(bool aAllowAsyncInit);
 
-    static PluginLibrary* LoadModule(uint32_t aPluginId);
+    static PluginLibrary* LoadModule(uint32_t aPluginId, nsPluginTag* aPluginTag);
 
     static PluginModuleContentParent* Initialize(mozilla::ipc::Transport* aTransport,
                                                  base::ProcessId aOtherProcess);
 
     static void OnLoadPluginResult(const uint32_t& aPluginId, const bool& aResult);
     static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
 
     virtual ~PluginModuleContentParent();
@@ -492,17 +492,18 @@ private:
 #if defined(XP_WIN) || defined(XP_MACOSX)
     virtual nsresult NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error) override;
 #endif
 
     virtual void ActorDestroy(ActorDestroyReason why) override;
 
     // aFilePath is UTF8, not native!
     explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId,
-                                      int32_t aSandboxLevel);
+                                      int32_t aSandboxLevel,
+                                      bool aAllowAsyncInit);
 
     CrashReporterParent* CrashReporter();
 
     void CleanupFromTimeout(const bool aByHangUI);
 
     virtual void UpdatePluginTimeout() override;
 
 #ifdef MOZ_ENABLE_PROFILER_SPS