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/. */
9 #include "nsDirectoryService.h"
10 #include "nsDirectoryServiceDefs.h"
11 #include "mozilla/GeckoArgs.h"
12 #include "mozilla/ipc/ProcessChild.h"
14 #include "nsZipArchive.h"
15 #include "nsNetUtil.h"
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
) {
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
;
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
));
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
;
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
) {
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.
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.
81 RefPtr
<nsZipArchive
> zipReader
= nsZipArchive::OpenArchive(file
);
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
);
96 return NS_ERROR_FILE_CORRUPTED
;
101 sReader
[aType
] = zipReader
;
102 sOuterReader
[aType
] = outerReader
;
108 nsresult
Omnijar::FallibleInit(nsIFile
* aGrePath
, nsIFile
* aAppPath
) {
109 // Even on error we do not want to come here again.
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
);
122 void Omnijar::Init(nsIFile
* aGrePath
, nsIFile
* aAppPath
) {
123 nsresult rv
= FallibleInit(aGrePath
, aAppPath
);
125 MOZ_CRASH_UNSAFE_PRINTF("Omnijar::Init failed: %s",
126 mozilla::GetStaticErrorName(rv
));
130 void Omnijar::CleanUp() {
133 sInitialized
= false;
136 already_AddRefed
<nsZipArchive
> Omnijar::GetReader(nsIFile
* aPath
) {
137 MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
143 rv
= sPath
[GRE
]->Equals(aPath
, &equals
);
144 if (NS_SUCCEEDED(rv
) && equals
) {
145 return IsNested(GRE
) ? GetOuterReader(GRE
) : GetReader(GRE
);
149 rv
= sPath
[APP
]->Equals(aPath
, &equals
);
150 if (NS_SUCCEEDED(rv
) && equals
) {
151 return IsNested(APP
) ? GetOuterReader(APP
) : GetReader(APP
);
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
))) {
169 rv
= sPath
[GRE
]->Equals(aPath
, &equals
);
170 if (NS_SUCCEEDED(rv
) && equals
) {
171 return IsNested(GRE
) ? GetReader(GRE
) : nullptr;
175 rv
= sPath
[APP
]->Equals(aPath
, &equals
);
176 if (NS_SUCCEEDED(rv
) && equals
) {
177 return IsNested(APP
) ? GetReader(APP
) : nullptr;
183 nsresult
Omnijar::GetURIString(Type aType
, nsACString
& aResult
) {
184 MOZ_ASSERT(IsInitialized(), "Omnijar not initialized");
188 // Return an empty string for APP in the unified case.
189 if ((aType
== APP
) && sIsUnified
) {
193 nsAutoCString omniJarSpec
;
195 nsresult rv
= NS_GetURLSpecFromActualFile(sPath
[aType
], omniJarSpec
);
196 if (NS_WARN_IF(NS_FAILED(rv
))) {
201 if (IsNested(aType
)) {
204 aResult
+= omniJarSpec
;
206 if (IsNested(aType
)) {
207 aResult
+= "/" MOZ_STRINGIFY(OMNIJAR_NAME
) "!";
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
))) {
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()
227 # define ANDROID_DIAGNOSTIC_CRASH_OR_EXIT(_msg)
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");
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
))))) {
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.)
262 Init(greOmni
, appOmni
);
264 // We should never have an appOmni without a greOmni.
265 MOZ_ASSERT(!appOmni
);
269 #undef ANDROID_DIAGNOSTIC_CRASH_OR_EXIT
271 } /* namespace mozilla */