From 4ae600a9d9a9ab0fb27b86ec38e22b3ed1c2ab3d Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Sun, 27 May 2012 22:40:48 -0400 Subject: [PATCH] Bug 692255 - Get rid of prefetch files on Windows for faster startup. r=rstrong --- .../shell/src/nsWindowsShellService.cpp | 133 +++++++++ .../shell/src/nsWindowsShellService.h | 9 +- browser/installer/windows/nsis/shared.nsh | 1 + .../components/maintenanceservice/Makefile.in | 1 + .../maintenanceservice/maintenanceservice.cpp | 22 +- .../maintenanceservice/prefetch.cpp | 255 ++++++++++++++++++ .../components/maintenanceservice/prefetch.h | 38 +++ .../registrycertificates.cpp | 1 + .../maintenanceservice/workmonitor.cpp | 3 + toolkit/mozapps/update/common/Makefile.in | 1 + toolkit/mozapps/update/common/pathhash.h | 9 - .../mozapps/update/common/updatehelper.cpp | 17 +- toolkit/mozapps/update/common/updatehelper.h | 13 + 13 files changed, 488 insertions(+), 15 deletions(-) create mode 100644 toolkit/components/maintenanceservice/prefetch.cpp create mode 100644 toolkit/components/maintenanceservice/prefetch.h diff --git a/browser/components/shell/src/nsWindowsShellService.cpp b/browser/components/shell/src/nsWindowsShellService.cpp index 21aaf1115743..b2b7bac7588c 100644 --- a/browser/components/shell/src/nsWindowsShellService.cpp +++ b/browser/components/shell/src/nsWindowsShellService.cpp @@ -26,6 +26,7 @@ #include "nsUnicharUtils.h" #include "nsIWinTaskbar.h" #include "nsISupportsPrimitives.h" +#include "nsThreadUtils.h" #include "windows.h" #include "shellapi.h" @@ -52,6 +53,11 @@ #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" +// We clear the prefetch files one time after the browser is started after +// 60 seconds. After this is done once we set a pref so this will never happen +// again except in updater code. +#define CLEAR_PREFETCH_TIMEOUT_MS 60000 + NS_IMPL_ISUPPORTS2(nsWindowsShellService, nsIWindowsShellService, nsIShellService) static nsresult @@ -189,6 +195,16 @@ static SETTING gDDESettings[] = { { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) } }; +#if defined(MOZ_MAINTENANCE_SERVICE) + +#define ONLY_SERVICE_LAUNCHING +#include "updatehelper.h" +#include "updatehelper.cpp" + +static const char kPrefetchClearedPref[] = "app.update.service.prefetchCleared"; +static nsCOMPtr sThread; +#endif + nsresult GetHelperPath(nsAutoString& aPath) { @@ -908,6 +924,123 @@ nsWindowsShellService::SetDesktopBackgroundColor(PRUint32 aColor) return regKey->Close(); } +nsWindowsShellService::nsWindowsShellService() : + mCheckedThisSession(false) +{ +#if defined(MOZ_MAINTENANCE_SERVICE) + + // Check to make sure the service is installed + PRUint32 installed = 0; + nsCOMPtr regKey = + do_CreateInstance("@mozilla.org/windows-registry-key;1"); + if (!regKey || + NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, + NS_LITERAL_STRING( + "SOFTWARE\\Mozilla\\MaintenanceService"), + nsIWindowsRegKey::ACCESS_READ | + nsIWindowsRegKey::WOW64_64)) || + NS_FAILED(regKey->ReadIntValue(NS_LITERAL_STRING("Installed"), + &installed)) || + !installed) { + return; + } + + // check to see if we have attempted to do the one time operation of clearing + // the prefetch. + bool prefetchCleared; + nsCOMPtr prefBranch; + nsCOMPtr prefs = + do_GetService(NS_PREFSERVICE_CONTRACTID); + if (!prefs || + NS_FAILED(prefs->GetBranch(nsnull, getter_AddRefs(prefBranch))) || + (NS_SUCCEEDED(prefBranch->GetBoolPref(kPrefetchClearedPref, + &prefetchCleared)) && + prefetchCleared)) { + return; + } + + // In a minute after startup is definitely complete, launch the + // service command. + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + if (mTimer) { + mTimer->InitWithFuncCallback( + nsWindowsShellService::LaunchPrefetchClearCommand, + nsnull, CLEAR_PREFETCH_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT); + } +#endif +} + +nsWindowsShellService::~nsWindowsShellService() +{ +#if defined(MOZ_MAINTENANCE_SERVICE) + if (mTimer) { + mTimer->Cancel(); + mTimer = nsnull; + } + if (sThread) { + sThread->Shutdown(); + sThread = nsnull; + } +#endif +} + +#if defined(MOZ_MAINTENANCE_SERVICE) + +class ClearPrefetchEvent : public nsRunnable { +public: + ClearPrefetchEvent() + { + } + + NS_IMETHOD Run() + { + // Start the service command + LPCWSTR updaterServiceArgv[2]; + updaterServiceArgv[0] = L"MozillaMaintenance"; + updaterServiceArgv[1] = L"clear-prefetch"; + // If this command fails, it is not critical as prefetch will be cleared + // on the next software update. + StartServiceCommand(NS_ARRAY_LENGTH(updaterServiceArgv), + updaterServiceArgv); + return NS_OK; + } +}; +#endif + +/** + * For faster startup we attempt to clear the prefetch if the maintenance + * service is installed. Please see the definition of ClearPrefetch() + * in toolkit/components/maintenanceservice/prefetch.cpp for more info. + * For now the only application that gets prefetch cleaned is Firefox + * since we have not done performance checking for other applications. + * This is done on every update but also there is a one time operation done + * from within the program for first time installs. + */ +#if defined(MOZ_MAINTENANCE_SERVICE) +void +nsWindowsShellService::LaunchPrefetchClearCommand(nsITimer *aTimer, void*) +{ + // Make sure we don't call this again from the application, it will be + // called on each application update instead. + nsCOMPtr prefBranch; + nsCOMPtr prefs = + do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + if (NS_SUCCEEDED(prefs->GetBranch(nsnull, getter_AddRefs(prefBranch)))) { + prefBranch->SetBoolPref(kPrefetchClearedPref, true); + } + } + + // Starting the sevice can take a bit of time and we don't want to block the + // main thread, so start an event on another thread to handle the operation + NS_NewThread(getter_AddRefs(sThread)); + if (sThread) { + nsCOMPtr prefetchEvent = new ClearPrefetchEvent(); + sThread->Dispatch(prefetchEvent, NS_DISPATCH_NORMAL); + } +} +#endif + NS_IMETHODIMP nsWindowsShellService::OpenApplicationWithURI(nsILocalFile* aApplication, const nsACString& aURI) diff --git a/browser/components/shell/src/nsWindowsShellService.h b/browser/components/shell/src/nsWindowsShellService.h index b3c8fc16d0c9..50d2783800c2 100644 --- a/browser/components/shell/src/nsWindowsShellService.h +++ b/browser/components/shell/src/nsWindowsShellService.h @@ -9,6 +9,7 @@ #include "nscore.h" #include "nsStringAPI.h" #include "nsIWindowsShellService.h" +#include "nsITimer.h" #include #include @@ -16,8 +17,8 @@ class nsWindowsShellService : public nsIWindowsShellService { public: - nsWindowsShellService() : mCheckedThisSession(false) {}; - virtual ~nsWindowsShellService() {}; + nsWindowsShellService(); + virtual ~nsWindowsShellService(); NS_DECL_ISUPPORTS NS_DECL_NSISHELLSERVICE @@ -27,6 +28,10 @@ protected: bool IsDefaultBrowserVista(bool* aIsDefaultBrowser); private: +#if defined(MOZ_MAINTENANCE_SERVICE) + static void LaunchPrefetchClearCommand(nsITimer *aTimer, void*); + nsCOMPtr mTimer; +#endif bool mCheckedThisSession; }; diff --git a/browser/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh index fd038d697480..e4e2c25cc877 100755 --- a/browser/installer/windows/nsis/shared.nsh +++ b/browser/installer/windows/nsis/shared.nsh @@ -587,6 +587,7 @@ SetRegView 64 ${EndIf} DeleteRegKey HKLM "$R0" + WriteRegStr HKLM "$R0" "prefetchProcessName" "FIREFOX" WriteRegStr HKLM "$R0\0" "name" "${CERTIFICATE_NAME}" WriteRegStr HKLM "$R0\0" "issuer" "${CERTIFICATE_ISSUER}" ${If} ${RunningX64} diff --git a/toolkit/components/maintenanceservice/Makefile.in b/toolkit/components/maintenanceservice/Makefile.in index c67cc2f3f5a2..edadbd905852 100644 --- a/toolkit/components/maintenanceservice/Makefile.in +++ b/toolkit/components/maintenanceservice/Makefile.in @@ -16,6 +16,7 @@ CPPSRCS = \ certificatecheck.cpp \ servicebase.cpp \ registrycertificates.cpp \ + prefetch.cpp \ $(NULL) # For debugging purposes only diff --git a/toolkit/components/maintenanceservice/maintenanceservice.cpp b/toolkit/components/maintenanceservice/maintenanceservice.cpp index 532ec56a1cab..b60d4b3de05f 100644 --- a/toolkit/components/maintenanceservice/maintenanceservice.cpp +++ b/toolkit/components/maintenanceservice/maintenanceservice.cpp @@ -14,6 +14,7 @@ #include "workmonitor.h" #include "uachelper.h" #include "updatehelper.h" +#include "prefetch.h" SERVICE_STATUS gSvcStatus = { 0 }; SERVICE_STATUS_HANDLE gSvcStatusHandle = NULL; @@ -26,6 +27,18 @@ bool gServiceControlStopping = false; BOOL GetLogDirectoryPath(WCHAR *path); +/** + * Wraps all commands that should be executed by the service on each install + * and upgrade. +*/ +void +RunCommandsForEachInstallAndUpgrade() +{ + LOG(("Running install/upgrade commands...\n")); + ClearKnownPrefetch(); + LOG(("Finished install/upgrade commands\n")); +} + int wmain(int argc, WCHAR **argv) { @@ -52,7 +65,9 @@ wmain(int argc, WCHAR **argv) } LOG(("...\n")); - if (!SvcInstall(action)) { + bool ret = SvcInstall(action); + RunCommandsForEachInstallAndUpgrade(); + if (!ret) { LOG(("Could not install service (%d)\n", GetLastError())); LogFinish(); return 1; @@ -69,7 +84,10 @@ wmain(int argc, WCHAR **argv) LogInit(updatePath, L"maintenanceservice-install.log"); } LOG(("Upgrading service if installed...\n")); - if (!SvcInstall(UpgradeSvc)) { + + bool ret = SvcInstall(UpgradeSvc); + RunCommandsForEachInstallAndUpgrade(); + if (!ret) { LOG(("Could not upgrade service (%d)\n", GetLastError())); LogFinish(); return 1; diff --git a/toolkit/components/maintenanceservice/prefetch.cpp b/toolkit/components/maintenanceservice/prefetch.cpp new file mode 100644 index 000000000000..7215fc86a10b --- /dev/null +++ b/toolkit/components/maintenanceservice/prefetch.cpp @@ -0,0 +1,255 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Maintenance service prefetch cleaning. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian R. Bondy + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include "servicebase.h" +#include "updatehelper.h" +#include "nsWindowsHelpers.h" +#define MAX_KEY_LENGTH 255 + +/** + * We found that prefetch actually causes large applications like Firefox + * to startup slower. This will get rid of the Windows prefetch files for + * applications like firefox (FIREFOX-*.pf files) and instead replace them + * with 0 byte files which are read only. Windows will not use prefetch + * if the associated prefetch file is a 0 byte read only file. + * Some of the problems with prefetch relating to Windows and Firefox: + * - Prefetch reads in a lot before we even run (fonts, plugins, etc...) + * - Prefetch happens before our code runs, so it delays UI showing. + * - Prefetch does not use windows readahead. + * Previous test data on an acer i7 laptop with a 5400rpm HD showed startup + * time difference was 1.6s (without prefetch) vs 2.6s+ with prefetch. + * The "Windows Internals" book mentions that prefetch can be disabled for + * the whole system only, so there is no other application specific way to + * disable it. + * + * @param prefetchProcessName The name of the process who's prefetch files + * should be cleared. + * @return TRUE if no errors occurred during the clear operation. +*/ +BOOL +ClearPrefetch(LPCWSTR prefetchProcessName) +{ + LOG(("Clearing prefetch files...\n")); + size_t prefetchProcessNameLength = wcslen(prefetchProcessName); + + // Make sure we were passed in a safe value for the prefetch process name + // because it will be appended to a filepath and deleted. + // We check for < 2 to avoid things like "." as the path + // We check for a max path of MAX_PATH - 10 because we add \\ and '.EXE-*.pf' + if (wcsstr(prefetchProcessName, L"..") || + wcsstr(prefetchProcessName, L"\\") || + wcsstr(prefetchProcessName, L"*") || + wcsstr(prefetchProcessName, L"/") || + prefetchProcessNameLength < 2 || + prefetchProcessNameLength >= (MAX_PATH - 10)) { + LOG(("Prefetch path to clear is not safe\n")); + return FALSE; + } + + // Quick shortcut to make sure we don't try to clear multiple times for + // different FIREFOX installs. + static WCHAR lastPrefetchProcessName[MAX_PATH - 10] = { '\0' }; + if (!wcscmp(lastPrefetchProcessName, prefetchProcessName)) { + LOG(("Already processed process name\n")); + return FALSE; + } + wcscpy(lastPrefetchProcessName, prefetchProcessName); + + // Obtain the windows prefetch directory path. + WCHAR prefetchPath[MAX_PATH + 1]; + if (!GetWindowsDirectoryW(prefetchPath, + sizeof(prefetchPath) / + sizeof(prefetchPath[0]))) { + LOG(("Could not obtain windows directory\n")); + return FALSE; + } + if (!PathAppendSafe(prefetchPath, L"prefetch")) { + LOG(("Could not obtain prefetch directory\n")); + return FALSE; + } + + size_t prefetchDirLen = wcslen(prefetchPath); + WCHAR prefetchSearchFile[MAX_PATH + 1]; + // We know this is safe based on the check at the start of this function + wsprintf(prefetchSearchFile, L"\\%s.EXE-*.pf", prefetchProcessName); + // Append the search file to the full path + wcscpy(prefetchPath + prefetchDirLen, prefetchSearchFile); + + // Find the first path matching and get a find handle for future calls. + WIN32_FIND_DATAW findFileData; + HANDLE findHandle = FindFirstFileW(prefetchPath, &findFileData); + if (INVALID_HANDLE_VALUE == findHandle) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + LOG(("No files matching firefox.exe prefetch path.\n")); + return TRUE; + } else { + LOG(("Error finding firefox.exe prefetch files. (%d)\n", + GetLastError())); + return FALSE; + } + } + + BOOL deletedAllFFPrefetch = TRUE; + do { + // Reset back to the prefetch directory, we know from an above check that + // we aren't exceeding MAX_PATH + 1 characters with prefetchDirLen + 1. + // From above we know: prefetchPath[prefetchDirLen] == L'\\'; + prefetchPath[prefetchDirLen + 1] = L'\0'; + + // Get the new file's prefetch path + LPWSTR filenameOffsetInBuffer = prefetchPath + prefetchDirLen + 1; + if (wcslen(findFileData.cFileName) + prefetchDirLen + 1 > MAX_PATH) { + LOG(("Error appending prefetch path %ls, path is too long. (%d)\n", + findFileData.cFileName, GetLastError())); + deletedAllFFPrefetch = FALSE; + continue; + } + if (!PathAppendSafe(filenameOffsetInBuffer, findFileData.cFileName)) { + LOG(("Error appending prefetch path %ls. (%d)\n", findFileData.cFileName, + GetLastError())); + deletedAllFFPrefetch = FALSE; + continue; + } + + // Delete the prefetch file and replace it with a blank read only file + HANDLE prefetchFile = + CreateFile(prefetchPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (INVALID_HANDLE_VALUE == prefetchFile) { + LOG(("Error replacing prefetch path %ls. (%d)\n", findFileData.cFileName, + GetLastError())); + deletedAllFFPrefetch = FALSE; + continue; + } + + CloseHandle(prefetchFile); + + DWORD attributes = GetFileAttributes(prefetchPath); + if (INVALID_FILE_ATTRIBUTES == attributes) { + LOG(("Could not get/set attributes on prefetch file: %ls. (%d)\n", + findFileData.cFileName, GetLastError())); + continue; + } + + if (!SetFileAttributes(prefetchPath, + attributes | FILE_ATTRIBUTE_READONLY)) { + LOG(("Could not set read only on prefetch file: %ls. (%d)\n", + findFileData.cFileName, GetLastError())); + continue; + } + + LOG(("Prefetch file cleared and set to read-only successfully: %ls\n", + prefetchPath)); + } while (FindNextFileW(findHandle, &findFileData)); + LOG(("Done searching prefetch paths. (%d)\n", GetLastError())); + + // Cleanup after ourselves. + FindClose(findHandle); + return deletedAllFFPrefetch; +} + +/** + * Clears all prefetch files specified in the installation dirctories + * @return FALSE if there was an error clearing the known prefetch directories +*/ +BOOL +ClearKnownPrefetch() +{ + // The service always uses the 64-bit registry key + HKEY baseKeyRaw; + LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + BASE_SERVICE_REG_KEY, 0, + KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); + if (retCode != ERROR_SUCCESS) { + LOG(("Could not open maintenance service base key. (%d)\n", retCode)); + return FALSE; + } + nsAutoRegKey baseKey(baseKeyRaw); + + // Get the number of subkeys. + DWORD subkeyCount = 0; + retCode = RegQueryInfoKeyW(baseKey, NULL, NULL, NULL, &subkeyCount, NULL, + NULL, NULL, NULL, NULL, NULL, NULL); + if (retCode != ERROR_SUCCESS) { + LOG(("Could not query info key: %d\n", retCode)); + return FALSE; + } + + // Enumerate the subkeys, each subkey represents an install + for (DWORD i = 0; i < subkeyCount; i++) { + WCHAR subkeyBuffer[MAX_KEY_LENGTH]; + DWORD subkeyBufferCount = MAX_KEY_LENGTH; + retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, + &subkeyBufferCount, NULL, + NULL, NULL, NULL); + if (retCode != ERROR_SUCCESS) { + LOG(("Could not enum installations: %d\n", retCode)); + return FALSE; + } + + // Open the subkey + HKEY subKeyRaw; + retCode = RegOpenKeyExW(baseKey, + subkeyBuffer, + 0, + KEY_READ | KEY_WOW64_64KEY, + &subKeyRaw); + nsAutoRegKey subKey(subKeyRaw); + if (retCode != ERROR_SUCCESS) { + LOG(("Could not open subkey: %d\n", retCode)); + continue; // Try the next subkey + } + + const int MAX_CHAR_COUNT = 256; + DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); + WCHAR prefetchProcessName[MAX_CHAR_COUNT] = { L'\0' }; + + // Get the prefetch process name from the registry + retCode = RegQueryValueExW(subKey, L"prefetchProcessName", 0, NULL, + (LPBYTE)prefetchProcessName, &valueBufSize); + if (retCode != ERROR_SUCCESS) { + LOG(("Could not obtain process name from registry: %d\n", retCode)); + continue; // Try the next subkey + } + + // The value for prefetch process name comes from HKLM so is trusted. + // We will do some sanity checks on it though inside ClearPrefetch. + ClearPrefetch(prefetchProcessName); + } + + return TRUE; +} diff --git a/toolkit/components/maintenanceservice/prefetch.h b/toolkit/components/maintenanceservice/prefetch.h new file mode 100644 index 000000000000..3dda95608176 --- /dev/null +++ b/toolkit/components/maintenanceservice/prefetch.h @@ -0,0 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Maintenance service prefetch cleaning. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2012 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian R. Bondy + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +BOOL ClearKnownPrefetch(); diff --git a/toolkit/components/maintenanceservice/registrycertificates.cpp b/toolkit/components/maintenanceservice/registrycertificates.cpp index 9ce867f9d171..29554c097235 100644 --- a/toolkit/components/maintenanceservice/registrycertificates.cpp +++ b/toolkit/components/maintenanceservice/registrycertificates.cpp @@ -10,6 +10,7 @@ #include "pathhash.h" #include "nsWindowsHelpers.h" #include "servicebase.h" +#include "updatehelper.h" #define MAX_KEY_LENGTH 255 /** diff --git a/toolkit/components/maintenanceservice/workmonitor.cpp b/toolkit/components/maintenanceservice/workmonitor.cpp index 4148767d42c3..f283b88b5a3c 100644 --- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ b/toolkit/components/maintenanceservice/workmonitor.cpp @@ -24,6 +24,7 @@ #include "uachelper.h" #include "updatehelper.h" #include "errors.h" +#include "prefetch.h" // Wait 15 minutes for an update operation to run at most. // Updates usually take less than a minute so this seems like a @@ -482,6 +483,8 @@ ExecuteServiceCommand(int argc, LPWSTR *argv) // because the service self updates itself and the service // installer will stop the service. LOG(("Service command %ls complete.\n", argv[2])); + } else if (!lstrcmpi(argv[2], L"clear-prefetch")) { + result = ClearKnownPrefetch(); } else { LOG(("Service command not recognized: %ls.\n", argv[2])); // result is already set to FALSE diff --git a/toolkit/mozapps/update/common/Makefile.in b/toolkit/mozapps/update/common/Makefile.in index 14e7d2868c9b..f5fae631c3a0 100644 --- a/toolkit/mozapps/update/common/Makefile.in +++ b/toolkit/mozapps/update/common/Makefile.in @@ -34,6 +34,7 @@ CPPSRCS += updatehelper.cpp \ $(NULL) EXPORTS = updatehelper.h \ + updatehelper.cpp \ uachelper.h \ pathhash.h \ $(NULL) diff --git a/toolkit/mozapps/update/common/pathhash.h b/toolkit/mozapps/update/common/pathhash.h index 507b34646830..a238317e17b4 100644 --- a/toolkit/mozapps/update/common/pathhash.h +++ b/toolkit/mozapps/update/common/pathhash.h @@ -16,13 +16,4 @@ BOOL CalculateRegistryPathFromFilePath(const LPCWSTR filePath, LPWSTR registryPath); -// The test only fallback key, as its name implies, is only present on machines -// that will use automated tests. Since automated tests always run from a -// different directory for each test, the presence of this key bypasses the -// "This is a valid installation directory" check. This key also stores -// the allowed name and issuer for cert checks so that the cert check -// code can still be run unchanged. -#define TEST_ONLY_FALLBACK_KEY_PATH \ - L"SOFTWARE\\Mozilla\\MaintenanceService\\3932ecacee736d366d6436db0f55bce4" - #endif diff --git a/toolkit/mozapps/update/common/updatehelper.cpp b/toolkit/mozapps/update/common/updatehelper.cpp index bc9d2e7b59c4..27b8055c0b02 100644 --- a/toolkit/mozapps/update/common/updatehelper.cpp +++ b/toolkit/mozapps/update/common/updatehelper.cpp @@ -3,6 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include + +// Needed for CreateToolhelp32Snapshot +#include +#ifndef ONLY_SERVICE_LAUNCHING + #include #include "shlobj.h" #include "updatehelper.h" @@ -10,8 +15,6 @@ // Needed for PathAppendW #include -// Needed for CreateToolhelp32Snapshot -#include #pragma comment(lib, "shlwapi.lib") WCHAR* MakeCommandLine(int argc, WCHAR **argv); @@ -236,6 +239,8 @@ StartServiceUpdate(int argc, LPWSTR *argv) return svcUpdateProcessStarted; } +#endif + /** * Executes a maintenance service command * @@ -294,6 +299,8 @@ StartServiceCommand(int argc, LPCWSTR* argv) return lastError; } +#ifndef ONLY_SERVICE_LAUNCHING + /** * Launch a service initiated action for a software update with the * specified arguments. @@ -403,6 +410,8 @@ WriteStatusFailure(LPCWSTR updateDirPath, int errorCode) return ok && wrote == toWrite; } +#endif + /** * Waits for a service to enter a stopped state. * This function does not stop the service, it just blocks until the service @@ -535,6 +544,8 @@ WaitForServiceStop(LPCWSTR serviceName, DWORD maxWaitSeconds) return lastServiceState; } +#ifndef ONLY_SERVICE_LAUNCHING + /** * Determines if there is at least one process running for the specified * application. A match will be found across any session for any user. @@ -620,6 +631,8 @@ DoesFallbackKeyExist() return TRUE; } +#endif + /** * Determines if the file system for the specified file handle is local * @param file path to check the filesystem type for, must be at most MAX_PATH diff --git a/toolkit/mozapps/update/common/updatehelper.h b/toolkit/mozapps/update/common/updatehelper.h index 9c9c88284483..84e015b46109 100644 --- a/toolkit/mozapps/update/common/updatehelper.h +++ b/toolkit/mozapps/update/common/updatehelper.h @@ -15,5 +15,18 @@ DWORD WaitForServiceStop(LPCWSTR serviceName, DWORD maxWaitSeconds); DWORD WaitForProcessExit(LPCWSTR filename, DWORD maxSeconds); BOOL DoesFallbackKeyExist(); BOOL IsLocalFile(LPCWSTR file, BOOL &isLocal); +DWORD StartServiceCommand(int argc, LPCWSTR* argv); #define SVC_NAME L"MozillaMaintenance" + +#define BASE_SERVICE_REG_KEY \ + L"SOFTWARE\\Mozilla\\MaintenanceService" + +// The test only fallback key, as its name implies, is only present on machines +// that will use automated tests. Since automated tests always run from a +// different directory for each test, the presence of this key bypasses the +// "This is a valid installation directory" check. This key also stores +// the allowed name and issuer for cert checks so that the cert check +// code can still be run unchanged. +#define TEST_ONLY_FALLBACK_KEY_PATH \ + BASE_SERVICE_REG_KEY L"\\3932ecacee736d366d6436db0f55bce4"