Bug 1378727: Part 1 - Add helper to enumerate cached ZipReader without locking issues. r?aswan
MozReview-Commit-ID: Kuw58LE1nYg
--- a/toolkit/mozapps/extensions/AddonManagerStartup.cpp
+++ b/toolkit/mozapps/extensions/AddonManagerStartup.cpp
@@ -20,16 +20,21 @@
#include "mozilla/Unused.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsAppRunner.h"
#include "nsContentUtils.h"
#include "nsIAddonInterposition.h"
+#include "nsIIOService.h"
+#include "nsIJARProtocolHandler.h"
+#include "nsIStringEnumerator.h"
+#include "nsIZipReader.h"
+#include "nsReadableUtils.h"
#include "nsXULAppAPI.h"
#include <stdlib.h>
namespace mozilla {
template <>
class MOZ_MUST_USE_TYPE GenericErrorResult<nsresult>
@@ -242,16 +247,34 @@ static bool
ParseJSON(JSContext* cx, nsACString& jsonData, JS::MutableHandleValue result)
{
NS_ConvertUTF8toUTF16 str(jsonData);
jsonData.Truncate();
return JS_ParseJSON(cx, str.Data(), str.Length(), result);
}
+static Result<nsCOMPtr<nsIZipReaderCache>, nsresult>
+GetJarCache()
+{
+ RefPtr<nsIIOService> ios = services::GetIOService();
+ NS_ENSURE_TRUE(ios, Err(NS_ERROR_FAILURE));
+
+ nsCOMPtr<nsIProtocolHandler> jarProto;
+ NS_TRY(ios->GetProtocolHandler("jar", getter_AddRefs(jarProto)));
+
+ nsCOMPtr<nsIJARProtocolHandler> jar = do_QueryInterface(jarProto);
+ MOZ_ASSERT(jar);
+
+ nsCOMPtr<nsIZipReaderCache> zipCache;
+ NS_TRY(jar->GetJARCache(getter_AddRefs(zipCache)));
+
+ return Move(zipCache);
+}
+
/*****************************************************************************
* JSON data handling
*****************************************************************************/
class MOZ_STACK_CLASS WrapperBase {
protected:
WrapperBase(JSContext* cx, JSObject* object)
@@ -694,16 +717,53 @@ AddonManagerStartup::DecodeBlob(JS::Hand
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
ErrorResult rv;
holder.Read(cx, result, rv);
return rv.StealNSResult();;
}
nsresult
+AddonManagerStartup::EnumerateZipFile(nsIFile* file, const nsACString& pattern,
+ uint32_t* countOut, char16_t*** entriesOut)
+{
+ NS_ENSURE_ARG_POINTER(file);
+ NS_ENSURE_ARG_POINTER(countOut);
+ NS_ENSURE_ARG_POINTER(entriesOut);
+
+ nsCOMPtr<nsIZipReaderCache> zipCache;
+ MOZ_TRY_VAR(zipCache, GetJarCache());
+
+ nsCOMPtr<nsIZipReader> zip;
+ NS_TRY(zipCache->GetZip(file, getter_AddRefs(zip)));
+
+ nsCOMPtr<nsIUTF8StringEnumerator> entries;
+ NS_TRY(zip->FindEntries(pattern, getter_AddRefs(entries)));
+
+ nsTArray<nsString> results;
+ bool hasMore;
+ while (NS_SUCCEEDED(entries->HasMore(&hasMore)) && hasMore) {
+ nsCString name;
+ NS_TRY(entries->GetNext(name));
+
+ results.AppendElement(NS_ConvertUTF8toUTF16(name));
+ }
+
+ auto strResults = MakeUnique<char16_t*[]>(results.Length());
+ for (uint32_t i = 0; i < results.Length(); i++) {
+ strResults[i] = ToNewUnicode(results[i]);
+ }
+
+ *countOut = results.Length();
+ *entriesOut = strResults.release();
+
+ return NS_OK;
+}
+
+nsresult
AddonManagerStartup::Reset()
{
MOZ_RELEASE_ASSERT(xpc::IsInAutomation());
mInitialized = false;
mExtensionPaths.Clear();
mThemePaths.Clear();
--- a/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
+++ b/toolkit/mozapps/extensions/amIAddonManagerStartup.idl
@@ -1,14 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
+interface nsIFile;
+
[scriptable, builtinclass, uuid(01dfa47b-87e4-4135-877b-586d033e1b5d)]
interface amIAddonManagerStartup : nsISupports
{
/**
* Reads and parses startup data from the addonState.json.lz4 file, checks
* for modifications, and returns the result.
*
* Returns null for an empty or nonexistent state file, but throws for an
@@ -26,16 +28,32 @@ interface amIAddonManagerStartup : nsISu
[implicit_jscontext]
jsval encodeBlob(in jsval value);
[implicit_jscontext]
jsval decodeBlob(in jsval value);
/**
+ * Enumerates over all entries in the given zip file matching the given
+ * pattern, and returns an array of their paths.
+ *
+ * This should be used in preference to manually opening or retrieving a
+ * ZipReader from the zip cache, since the former causes main thread IO and
+ * the latter can lead to file locking issues due to unpredictable GC behavior
+ * keeping the cached ZipReader alive after the cache is flushed.
+ *
+ * @param file The zip file to enumerate.
+ * @param pattern The pattern to match, as passed to nsIZipReader.findEntries.
+ */
+ void enumerateZipFile(in nsIFile file, in AUTF8String pattern,
+ [optional] out unsigned long count,
+ [retval, array, size_is(count)] out wstring entries);
+
+ /**
* Resets the internal state of the startup service, and allows
* initializeExtensions() to be called again. Does *not* fully unregister
* chrome registry locations for previously registered add-ons.
*
* NOT FOR USE OUTSIDE OF UNIT TESTS.
*/
void reset();
};