Bug 1891616: shared libraries for getting an installation's directory layout r=bytesized

This change creates the installation directory layout DLLs to be used in the versioned install
directory project outlined in https://bugzilla.mozilla.org/show_bug.cgi?id=1891600

These DLLs are both named InstallationDirLayout.dll, and their only
functionality is to return whether the current client installation uses
a single install directory (the current way), or versioned install
directories.

Eventually, the updater or installer will choose the appropriate version of this
directory to be installed on the client machine. Until we have that
functionality, the "single layout" version of the library will be
installed in the bin directory of the installation, and the "versioned
layout" version will be installed in a subdirectory.

More details are in the index.rst document included in this change.

Differential Revision: https://phabricator.services.mozilla.com/D236065
This commit is contained in:
Chris DuPuis
2025-03-05 15:57:41 +00:00
parent 9283f736fb
commit 7bdee519d1
12 changed files with 242 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
;+# 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/.
LIBRARY InstallationDirLayout
EXPORTS
GetInstallationDirLayoutType

View File

@@ -0,0 +1,11 @@
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef INSTALL_DIR_LAYOUT_H
#define INSTALL_DIR_LAYOUT_H
enum class InstallationDirLayoutType { Single, Versioned };
InstallationDirLayoutType GetInstallationDirLayoutType();
#endif // INSTALL_DIR_LAYOUT_H

View File

@@ -0,0 +1,65 @@
=============================
Installation Directory Layout
=============================
Rationale
===================
Firefox supports automatic downloading and applying of updates while the user is still using
the browser. However, once the update has been installed, files that the browser relies on
may have changed on disk, which caused the original implementation of update functionality to
force the user to restart the browser after updates. (See
_this bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1891600 for details and discussion.)
In order to let users continue to use the browser after updates are applied, the updater needs
to leave in place the files associated with the running browser, for as long as the browser's process
exists.
The approach we are taking to enable this behavior is a new installation layout called "versioned install directories".
What this involves is:
- Under the "base" install directory, there will be one or more "versioned" install directories,
with names based on the version of Firefox installed in them.
- Each versioned directory contains a complete installation of Firefox at the approapriate version.
- In the base install directory, there will be a launcher exectuable that launches the Firefox
executable in the appropriate versioned directory for the current Firefox version,
Example of "single" layout
This process allows all of the file resolution in Firefox to remain unchanged (for example,
C:\\Program Files\\Mozilla Firefox\\136.0.1a\\firefox.exe will load libraries from the directory
C:\\Program Files\\Mozilla Firefox\\136.0.1a\\). Most code will have no need to be aware of the change.
However, when applying updates to an installation,
the updater needs to know if it should:
- apply updates to a "single" install directory, and leave a single install directory in place (current behavior)
- apply updates to a single install directory, and migrate it to be a versioned install
- apply updates to a versioned install directory, using the new versioned install behavior
This means that the updater needs a way to know unambiguously whether an installation
is using a single or versioned layout. This is the functionality provided by this module.
Module contents
===============
The installation_dir_layout module provides two different implementations of a library `installation_dir_layout.dll`
This library has a single function, `GetInstallationDirLayoutType`, which returns an enumerated type.
The implementation of `installation_dir_layout.dll` in the `single` directory returns `InstallationDirLayoutType::Single`
The implementation of `installation_dir_layout.dll` in the `versioned` directory returns `InstallationDirLayoutType::Versioned`
The interface for both implementations is specified in InstallationDirLayout.h
DLL installation
================
When Firefox is installed or updated, the installer or updater will choose the appropriate version of `installation_dir_layout.dll`
to install. This version will be available to firefox.exe and its supporting utilities as a runtime library.
DLL usage
=========
Code that needs to know about the installation directory layout (such as updater and uninstaller) will load the installed
version of the DLL and call `GetInstallationDirLayoutType`.

View File

@@ -0,0 +1,11 @@
# 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/.
DIRS += ["single", "versioned"]
TEST_DIRS += [
"tests/gtest",
]
SPHINX_TREES["/installation_dir_layout"] = "docs"

View File

@@ -0,0 +1,9 @@
/* 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 https://mozilla.org/MPL/2.0/. */
#include "InstallationDirLayout.h"
InstallationDirLayoutType GetInstallationDirLayoutType() {
return InstallationDirLayoutType::Single;
}

View File

@@ -0,0 +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/.
LOCAL_INCLUDES = [".."]
SOURCES = [
"InstallationDirLayout.cpp",
]
DEFFILE = "../InstallationDirLayout.def"
# Note: This library is currently the default layout
# When we eventually switch to the default layout being versioned, the
# line below should be uncommented
# DIST_SUBDIR = "installation_dir_layout/single"
SharedLibrary("InstallationDirLayout")

View File

@@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "gtest/gtest.h"
#include <windows.h>
#include "InstallationDirLayout.h"
#include <string>
#include <iostream>
class InstallationDirLayoutTest : public ::testing::Test {
protected:
std::wstring dist_bin_dir;
void SetUp() override {
wchar_t pathbuf[MAX_PATH];
DWORD dwRet = GetCurrentDirectoryW(sizeof(pathbuf), pathbuf);
if (dwRet == 0) {
FAIL() << "Failed getting cwd";
}
if (dwRet > sizeof(pathbuf)) {
FAIL() << "Path was too long for buffer";
}
// We have the current directory in pathbuf. Now construct the path to
// dist/bin.
wchar_t* cut_location = wcsstr(pathbuf, L"\\_tests\\gtest");
if (!cut_location) {
FAIL() << "\\_tests\\gtest directory not found in path";
}
// Null-terminate the string at the cut location.
*cut_location = 0;
// And then stuff it into a wstring, so we can let the standard library
// worry about buffer limits
dist_bin_dir.append(pathbuf);
dist_bin_dir.append(L"\\dist\\bin");
}
void TearDown() override {}
};
using FuncType = InstallationDirLayoutType (*)();
TEST_F(InstallationDirLayoutTest, SingleLayoutTest) {
std::wstring runtimelib_path;
runtimelib_path.append(dist_bin_dir);
// Since this is the default, we don't need to access its by path.
runtimelib_path.append(L"\\InstallationDirLayout.dll");
std::wcout << L"Here is dll str: " << runtimelib_path << std::endl;
HINSTANCE hRuntimeLibrary =
LoadLibraryEx(runtimelib_path.c_str(), nullptr, 0);
ASSERT_NE(hRuntimeLibrary, nullptr);
FuncType dirLayoutFunc =
(FuncType)GetProcAddress(hRuntimeLibrary, "GetInstallationDirLayoutType");
ASSERT_NE(dirLayoutFunc, nullptr);
InstallationDirLayoutType layoutType = dirLayoutFunc();
ASSERT_EQ(layoutType, InstallationDirLayoutType::Single);
bool freeResult = FreeLibrary(hRuntimeLibrary);
ASSERT_TRUE(freeResult);
}
TEST_F(InstallationDirLayoutTest, VersionedLayoutTest) {
std::wstring runtimelib_path;
runtimelib_path.append(dist_bin_dir);
runtimelib_path.append(
L"\\installation_dir_layout\\versioned\\InstallationDirLayout.dll");
HINSTANCE hRuntimeLibrary =
LoadLibraryEx(runtimelib_path.c_str(), nullptr, 0);
ASSERT_NE(hRuntimeLibrary, nullptr);
FuncType dirLayoutFunc =
(FuncType)GetProcAddress(hRuntimeLibrary, "GetInstallationDirLayoutType");
ASSERT_NE(dirLayoutFunc, nullptr);
InstallationDirLayoutType layoutType = dirLayoutFunc();
ASSERT_EQ(layoutType, InstallationDirLayoutType::Versioned);
bool freeResult = FreeLibrary(hRuntimeLibrary);
ASSERT_TRUE(freeResult);
}

View File

@@ -0,0 +1,19 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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 https://mozilla.org/MPL/2.0/.
DEFINES["UNICODE"] = True
DEFINES["_UNICODE"] = True
LOCAL_INCLUDES += [
"/browser/app/installation_dir_layout",
]
Library("installation_dir_layout_test")
UNIFIED_SOURCES += [
"InstallationDirLayoutTest.cpp",
]
FINAL_LIBRARY = "xul-gtest"

View File

@@ -0,0 +1,9 @@
/* 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 https://mozilla.org/MPL/2.0/. */
#include "InstallationDirLayout.h"
InstallationDirLayoutType GetInstallationDirLayoutType() {
return InstallationDirLayoutType::Versioned;
}

View File

@@ -0,0 +1,13 @@
# 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/.
LOCAL_INCLUDES = [".."]
SOURCES = [
"InstallationDirLayout.cpp",
]
DIST_SUBDIR = "installation_dir_layout/versioned"
DEFFILE = "../InstallationDirLayout.def"
SharedLibrary("InstallationDirLayout")

View File

@@ -76,6 +76,7 @@ if CONFIG["CC_TYPE"] == "clang-cl":
if CONFIG["OS_ARCH"] == "WINNT":
RCINCLUDE = "splash.rc"
DIRS += [
"installation_dir_layout",
"pbproxy",
"winlauncher",
]

View File

@@ -91,6 +91,8 @@
#endif
#ifdef XP_WIN
@BINPATH@/@MOZ_CHILD_PROCESS_NAME@
@BINPATH@/@DLL_PREFIX@InstallationDirLayout@DLL_SUFFIX@
@BINPATH@/installation_dir_layout/versioned/@DLL_PREFIX@InstallationDirLayout@DLL_SUFFIX@
#if MOZ_PACKAGE_MSVC_DLLS
@BINPATH@/@MSVC_C_RUNTIME_DLL@
#ifdef MSVC_C_RUNTIME_1_DLL