Bug 982101 - Automatically activate plugins that are bundled inside of extensions. r=bsmedberg
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Sat, 19 Apr 2014 14:17:19 +0200
changeset 197850 46b65a3ccf6f0d2c61e6706d3767a224de10de06
parent 197849 f6b3c03454a4354ad2f2a214f36c8eafdda45e2e
child 197851 6022ca67befb0d749024085dd2678728565b38fb
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs982101
milestone31.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 982101 - Automatically activate plugins that are bundled inside of extensions. r=bsmedberg
browser/app/profile/firefox.js
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginTags.cpp
dom/plugins/base/nsPluginTags.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -666,16 +666,19 @@ pref("plugins.hideMissingPluginsNotifica
 #ifdef RELEASE_BUILD
 // For now, plugins other than Java and Flash are enabled in beta/release
 // and click-to-activate in earlier channels.
 pref("plugin.default.state", 2);
 #else
 pref("plugin.default.state", 1);
 #endif
 
+// Plugins bundled in XPIs are enabled by default.
+pref("plugin.defaultXpi.state", 2);
+
 // Flash is enabled by default, and Java is click-to-activate by default on
 // all channels.
 pref("plugin.state.flash", 2);
 pref("plugin.state.java", 1);
 
 // display door hanger if flash not installed
 pref("plugins.notifyMissingFlash", true);
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -138,18 +138,19 @@ static const char *kPrefJavaMIME = "plug
 // 0.09 the file encoding is changed to UTF-8, bug 420285
 // 0.10 added plugin versions on appropriate platforms, bug 427743
 // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
 // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
 // 0.13 add architecture and list of invalid plugins, bug 616271
 // 0.14 force refresh due to locale comparison fix, bug 611296
 // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
 // 0.16 version bump to avoid importing the plugin flags in newer versions
+// 0.17 added flag on whether plugin is loaded from an XPI
 // The current plugin registry version (and the maximum version we know how to read)
-static const char *kPluginRegistryVersion = "0.16";
+static const char *kPluginRegistryVersion = "0.17";
 // The minimum registry version we know how to read
 static const char *kMinimumRegistryVersion = "0.9";
 
 static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
 
 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
 
 #ifdef PLUGIN_LOGGING
@@ -1622,16 +1623,72 @@ int64_t GetPluginLastModifiedTime(const 
   }
 #else
   localfile->GetLastModifiedTime(&fileModTime);
 #endif
 
   return fileModTime;
 }
 
+bool
+GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
+                         const nsCOMPtr<nsISimpleEnumerator>& extensionDirs)
+{
+  if (!extensionDirs) {
+    return false;
+  }
+
+  bool hasMore;
+  while (NS_SUCCEEDED(extensionDirs->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> supports;
+    nsresult rv = extensionDirs->GetNext(getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> extDir(do_QueryInterface(supports, &rv));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> dir;
+    if (NS_FAILED(extDir->Clone(getter_AddRefs(dir)))) {
+      continue;
+    }
+
+    bool contains;
+    if (NS_FAILED(dir->Contains(pluginFile, true, &contains)) || !contains) {
+      continue;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+nsCOMPtr<nsISimpleEnumerator>
+GetExtensionDirectories()
+{
+  nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  if (!dirService) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> list;
+  nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
+                                NS_GET_IID(nsISimpleEnumerator),
+                                getter_AddRefs(list));
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+
+  return list;
+}
+
 struct CompareFilesByTime
 {
   bool
   LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
   {
     return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
   }
 
@@ -1685,27 +1742,33 @@ nsresult nsPluginHost::ScanPluginsDirect
 
     if (nsPluginsDir::IsPluginFile(dirEntry)) {
       pluginFiles.AppendElement(dirEntry);
     }
   }
 
   pluginFiles.Sort(CompareFilesByTime());
 
+  nsCOMPtr<nsISimpleEnumerator> extensionDirs = GetExtensionDirectories();
+  if (!extensionDirs) {
+    PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("Could not get extension directories."));
+  }
+
   bool warnOutdated = false;
 
   for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
     nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
 
     nsString utf16FilePath;
     rv = localfile->GetPath(utf16FilePath);
     if (NS_FAILED(rv))
       continue;
 
-    int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const bool fromExtension = GetPluginIsFromExtension(localfile, extensionDirs);
 
     // Look for it in our cache
     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
     nsRefPtr<nsPluginTag> pluginTag;
     RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
 
     bool seenBefore = false;
 
@@ -1776,17 +1839,17 @@ nsresult nsPluginHost::ScanPluginsDirect
         }
         mInvalidPlugins = invalidTag;
 
         // Mark aPluginsChanged so pluginreg is rewritten
         *aPluginsChanged = true;
         continue;
       }
 
-      pluginTag = new nsPluginTag(&info, fileModTime);
+      pluginTag = new nsPluginTag(&info, fileModTime, fromExtension);
       pluginFile.FreePluginInfo(info);
       if (!pluginTag)
         return NS_ERROR_OUT_OF_MEMORY;
 
       pluginTag->mLibrary = library;
       uint32_t state = pluginTag->GetBlocklistState();
 
       // If the blocklist says it is risky and we have never seen this
@@ -2267,24 +2330,26 @@ nsPluginHost::WritePluginInfo()
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mFullPath.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mVersion.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
-    // lastModifiedTimeStamp|canUnload|tag->mFlags
-    PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
+    // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
+    PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%c\n",
       tag->mLastModifiedTime,
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       false, // did store whether or not to unload in-process plugins
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       0, // legacy field for flags
       PLUGIN_REGISTRY_FIELD_DELIMITER,
+      tag->IsFromExtension(),
+      PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
     //description, name & mtypecount are on separate line
     PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
       (tag->mDescription.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mName.get()),
@@ -2481,30 +2546,33 @@ nsPluginHost::ReadPluginInfo()
 
     // If this is a registry from a different architecture then don't attempt to read it
     if (PL_strcmp(archValues[1], arch.get())) {
       return rv;
     }
   }
 
   // Registry v0.13 and upwards includes the list of invalid plugins
-  bool hasInvalidPlugins = (version >= "0.13");
+  const bool hasInvalidPlugins = (version >= "0.13");
 
   // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
   const bool hasValidFlags = (version < "0.16");
 
+  // Registry v0.17 and upwards store whether the plugin comes from an XPI.
+  const bool hasFromExtension = (version >= "0.17");
+
+#if defined(XP_MACOSX)
+  const bool hasFullPathInFileNameField = false;
+#else
+  const bool hasFullPathInFileNameField = (version < "0.11");
+#endif
+
   if (!ReadSectionHeader(reader, "PLUGINS"))
     return rv;
 
-#if defined(XP_MACOSX)
-  bool hasFullPathInFileNameField = false;
-#else
-  bool hasFullPathInFileNameField = (version < "0.11");
-#endif
-
   while (reader.NextLine()) {
     const char *filename;
     const char *fullpath;
     nsAutoCString derivedFileName;
 
     if (hasInvalidPlugins && *reader.LinePtr() == '[') {
       break;
     }
@@ -2540,23 +2608,28 @@ nsPluginHost::ReadPluginInfo()
     if (regHasVersion) {
       version = reader.LinePtr();
       if (!reader.NextLine())
         return rv;
     } else {
       version = "0";
     }
 
-    // lastModifiedTimeStamp|canUnload|tag.mFlag
-    if (reader.ParseLine(values, 3) != 3)
+    // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
+    const int count = hasFromExtension ? 4 : 3;
+    if (reader.ParseLine(values, count) != count)
       return rv;
 
     // If this is an old plugin registry mark this plugin tag to be refreshed
     int64_t lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
     uint32_t tagflag = atoi(values[2]);
+    bool fromExtension = false;
+    if (hasFromExtension) {
+      fromExtension = atoi(values[3]);
+    }
     if (!reader.NextLine())
       return rv;
 
     char *description = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
 
 #if MOZ_WIDGET_ANDROID
@@ -2617,17 +2690,17 @@ nsPluginHost::ReadPluginInfo()
     nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
       description,
       filename,
       fullpath,
       version,
       (const char* const*)mimetypes,
       (const char* const*)mimedescriptions,
       (const char* const*)extensions,
-      mimetypecount, lastmod, true);
+      mimetypecount, lastmod, fromExtension, true);
     if (heapalloced)
       delete [] heapalloced;
 
     // Import flags from registry into prefs for old registry versions
     if (hasValidFlags && !pluginStateImported) {
       tag->ImportFlagsToPrefs(tagflag);
     }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -25,16 +25,19 @@ using namespace mozilla;
 // These legacy flags are used in the plugin registry. The states are now
 // stored in prefs, but we still need to be able to import them.
 #define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
 // no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
 // no longer used                   0x0008    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_CLICKTOPLAY  0x0020    // this is a click-to-play plugin
 
+static const char kPrefDefaultEnabledState[] = "plugin.default.state";
+static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
+
 inline char* new_str(const char* str)
 {
   if (str == nullptr)
     return nullptr;
   
   char* result = new char[strlen(str) + 1];
   if (result != nullptr)
     return strcpy(result, str);
@@ -57,29 +60,32 @@ MakePrefNameForPlugin(const char* const 
 static nsCString
 GetStatePrefNameForPlugin(nsPluginTag* aTag)
 {
   return MakePrefNameForPlugin("state", aTag);
 }
 
 /* nsPluginTag */
 
-nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime)
+nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
+                         int64_t aLastModifiedTime,
+                         bool fromExtension)
   : mName(aPluginInfo->fName),
     mDescription(aPluginInfo->fDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aPluginInfo->fFileName),
     mFullPath(aPluginInfo->fFullPath),
     mVersion(aPluginInfo->fVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aPluginInfo->fMimeTypeArray,
            aPluginInfo->fMimeDescriptionArray,
            aPluginInfo->fExtensionArray,
            aPluginInfo->fVariantCount);
   EnsureMembersAreUTF8();
   FixupVersion();
 }
@@ -89,29 +95,31 @@ nsPluginTag::nsPluginTag(const char* aNa
                          const char* aFileName,
                          const char* aFullPath,
                          const char* aVersion,
                          const char* const* aMimeTypes,
                          const char* const* aMimeDescriptions,
                          const char* const* aExtensions,
                          int32_t aVariants,
                          int64_t aLastModifiedTime,
+                         bool fromExtension,
                          bool aArgsAreUTF8)
   : mName(aName),
     mDescription(aDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aFileName),
     mFullPath(aFullPath),
     mVersion(aVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
            static_cast<uint32_t>(aVariants));
   if (!aArgsAreUTF8)
     EnsureMembersAreUTF8();
   FixupVersion();
 }
 
@@ -360,18 +368,20 @@ nsPluginTag::GetEnabledState(uint32_t *a
                                     &enabledState);
   if (NS_SUCCEEDED(rv) &&
       enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return rv;
   }
 
-  enabledState = Preferences::GetInt("plugin.default.state",
-                                     nsIPluginTag::STATE_ENABLED);
+  const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi
+                                            : kPrefDefaultEnabledState;
+
+  enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED);
   if (enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return NS_OK;
   }
 
   return NS_ERROR_UNEXPECTED;
 }
@@ -569,8 +579,13 @@ nsPluginTag::InvalidateBlocklistState()
 
 NS_IMETHODIMP
 nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
 {
   MOZ_ASSERT(aLastModifiedTime);
   *aLastModifiedTime = mLastModifiedTime;
   return NS_OK;
 }
+
+bool nsPluginTag::IsFromExtension() const
+{
+  return mIsFromExtension;
+}
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -31,27 +31,30 @@ public:
   // These must match the STATE_* values in nsIPluginTag.idl
   enum PluginState {
     ePluginState_Disabled = 0,
     ePluginState_Clicktoplay = 1,
     ePluginState_Enabled = 2,
     ePluginState_MaxValue = 3,
   };
 
-  nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime);
+  nsPluginTag(nsPluginInfo* aPluginInfo,
+              int64_t aLastModifiedTime,
+              bool fromExtension);
   nsPluginTag(const char* aName,
               const char* aDescription,
               const char* aFileName,
               const char* aFullPath,
               const char* aVersion,
               const char* const* aMimeTypes,
               const char* const* aMimeDescriptions,
               const char* const* aExtensions,
               int32_t aVariants,
               int64_t aLastModifiedTime,
+              bool fromExtension,
               bool aArgsAreUTF8 = false);
   virtual ~nsPluginTag();
 
   void TryUnloadPlugin(bool inShutdown);
 
   // plugin is enabled and not blocklisted
   bool IsActive();
 
@@ -64,16 +67,18 @@ public:
   void SetPluginState(PluginState state);
 
   // import legacy flags from plugin registry into the preferences
   void ImportFlagsToPrefs(uint32_t flag);
 
   bool HasSameNameAndMimes(const nsPluginTag *aPluginTag) const;
   nsCString GetNiceFileName();
 
+  bool IsFromExtension() const;
+
   nsRefPtr<nsPluginTag> mNext;
   nsCString     mName; // UTF-8
   nsCString     mDescription; // UTF-8
   nsTArray<nsCString> mMimeTypes; // UTF-8
   nsTArray<nsCString> mMimeDescriptions; // UTF-8
   nsTArray<nsCString> mExtensions; // UTF-8
   PRLibrary     *mLibrary;
   nsRefPtr<nsNPAPIPlugin> mPlugin;
@@ -87,16 +92,17 @@ public:
 
   uint32_t      GetBlocklistState();
   void          InvalidateBlocklistState();
 
 private:
   nsCString     mNiceFileName; // UTF-8
   uint16_t      mCachedBlocklistState;
   bool          mCachedBlocklistStateValid;
+  bool          mIsFromExtension;
 
   void InitMime(const char* const* aMimeTypes,
                 const char* const* aMimeDescriptions,
                 const char* const* aExtensions,
                 uint32_t aVariantCount);
   nsresult EnsureMembersAreUTF8();
   void FixupVersion();
 };