Backed out changeset 70210dd7915c (bug 1926722) for causing LeakSanitizer failures...
[gecko.git] / xpcom / build / Omnijar.cpp
blob475c11114f5b088de83d82e6ec0827daa75730fd
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "Omnijar.h"
9 #include "nsDirectoryService.h"
10 #include "nsDirectoryServiceDefs.h"
11 #include "mozilla/GeckoArgs.h"
12 #include "mozilla/ipc/ProcessChild.h"
13 #include "nsIFile.h"
14 #include "nsZipArchive.h"
15 #include "nsNetUtil.h"
17 namespace mozilla {
19 StaticRefPtr<nsIFile> Omnijar::sPath[2];
20 StaticRefPtr<nsZipArchive> Omnijar::sReader[2];
21 StaticRefPtr<nsZipArchive> Omnijar::sOuterReader[2];
22 bool Omnijar::sInitialized = false;
23 bool Omnijar::sIsUnified = false;
25 static const char* sProp[2] = {NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR};
27 #define SPROP(Type) ((Type == mozilla::Omnijar::GRE) ? sProp[GRE] : sProp[APP])
29 void Omnijar::CleanUpOne(Type aType) {
30 if (sReader[aType]) {
31 sReader[aType] = nullptr;
33 if (sOuterReader[aType]) {
34 sOuterReader[aType] = nullptr;
36 sPath[aType] = nullptr;
39 nsresult Omnijar::InitOne(nsIFile* aPath, Type aType) {
40 nsCOMPtr<nsIFile> file;
41 if (aPath) {
42 file = aPath;
43 } else {
44 nsCOMPtr<nsIFile> dir;
45 MOZ_TRY(nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile),
46 getter_AddRefs(dir)));
47 constexpr auto kOmnijarName = nsLiteralCString{MOZ_STRINGIFY(OMNIJAR_NAME)};
48 MOZ_TRY(dir->Clone(getter_AddRefs(file)));
49 MOZ_TRY(file->AppendNative(kOmnijarName));
52 bool isFile = false;
53 if (NS_FAILED(file->IsFile(&isFile)) || !isFile) {
54 // If we're not using an omni.jar for GRE, and we don't have an
55 // omni.jar for APP, check if both directories are the same.
56 if ((aType == APP) && (!sPath[GRE])) {
57 nsCOMPtr<nsIFile> greDir, appDir;
58 bool equals;
59 nsDirectoryService::gService->Get(sProp[GRE], NS_GET_IID(nsIFile),
60 getter_AddRefs(greDir));
61 nsDirectoryService::gService->Get(sProp[APP], NS_GET_IID(nsIFile),
62 getter_AddRefs(appDir));
63 if (NS_SUCCEEDED(greDir->Equals(appDir, &equals)) && equals) {
64 sIsUnified = true;
67 return NS_OK;
70 // If we're using omni.jar on both GRE and APP and their path
71 // is the same, we're also in the unified case.
72 bool equals;
73 if ((aType == APP) && (sPath[GRE]) &&
74 NS_SUCCEEDED(sPath[GRE]->Equals(file, &equals)) && equals) {
75 // If we're using omni.jar on both GRE and APP and their path
76 // is the same, we're in the unified case.
77 sIsUnified = true;
78 return NS_OK;
81 RefPtr<nsZipArchive> zipReader = nsZipArchive::OpenArchive(file);
82 if (!zipReader) {
83 // As file has been checked to exist as file above, any error indicates
84 // that it is somehow corrupted internally.
85 return NS_ERROR_FILE_CORRUPTED;
88 RefPtr<nsZipArchive> outerReader;
89 RefPtr<nsZipHandle> handle;
90 // If we find a wrapped OMNIJAR, unwrap it.
91 if (NS_SUCCEEDED(nsZipHandle::Init(zipReader, MOZ_STRINGIFY(OMNIJAR_NAME),
92 getter_AddRefs(handle)))) {
93 outerReader = zipReader;
94 zipReader = nsZipArchive::OpenArchive(handle);
95 if (!zipReader) {
96 return NS_ERROR_FILE_CORRUPTED;
100 CleanUpOne(aType);
101 sReader[aType] = zipReader;
102 sOuterReader[aType] = outerReader;
103 sPath[aType] = file;
105 return NS_OK;
108 nsresult Omnijar::FallibleInit(nsIFile* aGrePath, nsIFile* aAppPath) {
109 // Even on error we do not want to come here again.
110 sInitialized = true;
112 // Let's always try to init both before returning any error for the benefit
113 // of callers that do not handle the error at all.
114 nsresult rvGRE = InitOne(aGrePath, GRE);
115 nsresult rvAPP = InitOne(aAppPath, APP);
116 MOZ_TRY(rvGRE);
117 MOZ_TRY(rvAPP);
119 return NS_OK;
122 void Omnijar::Init(nsIFile* aGrePath, nsIFile* aAppPath) {
123 nsresult rv = FallibleInit(aGrePath, aAppPath);
124 if (NS_FAILED(rv)) {
125 MOZ_CRASH_UNSAFE_PRINTF("Omnijar::Init failed: %s",
126 mozilla::GetStaticErrorName(rv));
130 void Omnijar::CleanUp() {
131 CleanUpOne(GRE);
132 CleanUpOne(APP);
133 sInitialized = false;
136 already_AddRefed<nsZipArchive> Omnijar::GetReader(nsIFile* aPath) {
137 MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
139 bool equals;
140 nsresult rv;
142 if (sPath[GRE]) {
143 rv = sPath[GRE]->Equals(aPath, &equals);
144 if (NS_SUCCEEDED(rv) && equals) {
145 return IsNested(GRE) ? GetOuterReader(GRE) : GetReader(GRE);
148 if (sPath[APP]) {
149 rv = sPath[APP]->Equals(aPath, &equals);
150 if (NS_SUCCEEDED(rv) && equals) {
151 return IsNested(APP) ? GetOuterReader(APP) : GetReader(APP);
154 return nullptr;
157 already_AddRefed<nsZipArchive> Omnijar::GetInnerReader(
158 nsIFile* aPath, const nsACString& aEntry) {
159 MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
161 if (!aEntry.EqualsLiteral(MOZ_STRINGIFY(OMNIJAR_NAME))) {
162 return nullptr;
165 bool equals;
166 nsresult rv;
168 if (sPath[GRE]) {
169 rv = sPath[GRE]->Equals(aPath, &equals);
170 if (NS_SUCCEEDED(rv) && equals) {
171 return IsNested(GRE) ? GetReader(GRE) : nullptr;
174 if (sPath[APP]) {
175 rv = sPath[APP]->Equals(aPath, &equals);
176 if (NS_SUCCEEDED(rv) && equals) {
177 return IsNested(APP) ? GetReader(APP) : nullptr;
180 return nullptr;
183 nsresult Omnijar::GetURIString(Type aType, nsACString& aResult) {
184 MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
186 aResult.Truncate();
188 // Return an empty string for APP in the unified case.
189 if ((aType == APP) && sIsUnified) {
190 return NS_OK;
193 nsAutoCString omniJarSpec;
194 if (sPath[aType]) {
195 nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec);
196 if (NS_WARN_IF(NS_FAILED(rv))) {
197 return rv;
200 aResult = "jar:";
201 if (IsNested(aType)) {
202 aResult += "jar:";
204 aResult += omniJarSpec;
205 aResult += "!";
206 if (IsNested(aType)) {
207 aResult += "/" MOZ_STRINGIFY(OMNIJAR_NAME) "!";
209 } else {
210 nsCOMPtr<nsIFile> dir;
211 nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile),
212 getter_AddRefs(dir));
213 nsresult rv = NS_GetURLSpecFromActualFile(dir, aResult);
214 if (NS_WARN_IF(NS_FAILED(rv))) {
215 return rv;
218 aResult += "/";
219 return NS_OK;
222 #if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
223 # define ANDROID_DIAGNOSTIC_CRASH_OR_EXIT(_msg) MOZ_CRASH(_msg)
224 #elif defined(MOZ_WIDGET_ANDROID)
225 # define ANDROID_DIAGNOSTIC_CRASH_OR_EXIT(_msg) ipc::ProcessChild::QuickExit()
226 #else
227 # define ANDROID_DIAGNOSTIC_CRASH_OR_EXIT(_msg)
228 #endif
230 void Omnijar::ChildProcessInit(int& aArgc, char** aArgv) {
231 nsCOMPtr<nsIFile> greOmni, appOmni;
233 // Android builds are always packaged, so if we can't find anything for
234 // greOmni, then this content process is useless, so kill it immediately.
235 // On release, we do this via QuickExit() because the crash volume is so
236 // high. See bug 1915788.
237 if (auto greOmniStr = geckoargs::sGREOmni.Get(aArgc, aArgv)) {
238 if (NS_WARN_IF(NS_FAILED(
239 XRE_GetFileFromPath(*greOmniStr, getter_AddRefs(greOmni))))) {
240 ANDROID_DIAGNOSTIC_CRASH_OR_EXIT("XRE_GetFileFromPath failed");
241 greOmni = nullptr;
243 } else {
244 ANDROID_DIAGNOSTIC_CRASH_OR_EXIT("sGREOmni.Get failed");
246 if (auto appOmniStr = geckoargs::sAppOmni.Get(aArgc, aArgv)) {
247 if (NS_WARN_IF(NS_FAILED(
248 XRE_GetFileFromPath(*appOmniStr, getter_AddRefs(appOmni))))) {
249 appOmni = nullptr;
253 // If we're unified, then only the -greomni flag is present
254 // (reflecting the state of sPath in the parent process) but that
255 // path should be used for both (not nullptr, which will try to
256 // invoke the directory service, which probably isn't up yet.)
257 if (!appOmni) {
258 appOmni = greOmni;
261 if (greOmni) {
262 Init(greOmni, appOmni);
263 } else {
264 // We should never have an appOmni without a greOmni.
265 MOZ_ASSERT(!appOmni);
269 #undef ANDROID_DIAGNOSTIC_CRASH_OR_EXIT
271 } /* namespace mozilla */