Bug 802423 - Updater needs to set oom_adj and nice appropriately. r=ehsan, a=tef+
authorDave Hylands <dhylands@mozilla.com>
Mon, 21 Jan 2013 12:22:16 -0800
changeset 118287 1ea93193e006fac3a84bfd06a5dc250effc5da8c
parent 118286 ae48617d7ff6ea00b7e010fae8bf939a78ef02a7
child 118288 dda716701b9db1b3b4d3057b979b5439a2b021dc
push id331
push userryanvm@gmail.com
push dateThu, 24 Jan 2013 00:20:48 +0000
reviewersehsan, tef
bugs802423
milestone18.0
Bug 802423 - Updater needs to set oom_adj and nice appropriately. r=ehsan, a=tef+
toolkit/mozapps/update/updater/updater.cpp
toolkit/xre/nsUpdateDriver.cpp
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -79,16 +79,24 @@ void LaunchMacPostProcess(const char* aA
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
 #define USE_EXECV
 #endif
 
 #if defined(MOZ_WIDGET_GONK)
 # include "automounter_gonk.h"
 # include <unistd.h>
 # include <android/log.h>
+# include <linux/ioprio.h>
+# include <sys/resource.h>
+
+// The only header file in bionic which has a function prototype for ioprio_set
+// is libc/include/sys/linux-unistd.h. However, linux-unistd.h conflicts
+// badly with unistd.h, so we declare the prototype for ioprio_set directly.
+extern "C" int ioprio_set(int which, int who, int ioprio);
+
 # define MAYBE_USE_HARD_LINKS 1
 static bool sUseHardLinks = true;
 #else
 # define MAYBE_USE_HARD_LINKS 0
 #endif
 
 #ifdef XP_WIN
 #include "updatehelper.h"
@@ -2394,16 +2402,45 @@ int NS_main(int argc, NS_tchar **argv)
   }
 
   if (sBackgroundUpdate) {
     LOG(("Performing a background update\n"));
   } else if (sReplaceRequest) {
     LOG(("Performing a replace request\n"));
   }
 
+#ifdef MOZ_WIDGET_GONK
+  const char *prioEnv = getenv("MOZ_UPDATER_PRIO");
+  if (prioEnv) {
+    int32_t prioVal;
+    int32_t oomScoreAdj;
+    int32_t ioprioClass;
+    int32_t ioprioLevel;
+    if (sscanf(prioEnv, "%d/%d/%d/%d",
+               &prioVal, &oomScoreAdj, &ioprioClass, &ioprioLevel) == 4) {
+      LOG(("MOZ_UPDATER_PRIO=%s", prioEnv));
+      if (setpriority(PRIO_PROCESS, 0, prioVal)) {
+        LOG(("setpriority(%d) failed, errno = %d", prioVal, errno));
+      }
+      if (ioprio_set(IOPRIO_WHO_PROCESS, 0,
+                     IOPRIO_PRIO_VALUE(ioprioClass, ioprioLevel))) {
+        LOG(("ioprio_set(%d,%d) failed: errno = %d",
+             ioprioClass, ioprioLevel, errno));
+      }
+      FILE *fs = fopen("/proc/self/oom_score_adj", "w");
+      if (fs) {
+        fprintf(fs, "%d", oomScoreAdj);
+        fclose(fs);
+      } else {
+        LOG(("Unable to open /proc/self/oom_score_adj for writing, errno = %d", errno));
+      }
+    }
+  }
+#endif
+
 #ifdef XP_WIN
   if (pid > 0) {
     HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid);
     // May return NULL if the parent process has already gone away.
     // Otherwise, wait for the parent process to exit before starting the
     // update.
     if (parent) {
       DWORD result = WaitForSingleObject(parent, 5000);
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -19,16 +19,18 @@
 #include "prenv.h"
 #include "nsVersionComparator.h"
 #include "nsXREDirProvider.h"
 #include "SpecialSystemDirectory.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsThreadUtils.h"
 #include "nsIXULAppInfo.h"
 #include "mozilla/Preferences.h"
+#include "nsPrintfCString.h"
+#include "mozilla/DebugOnly.h"
 
 #ifdef XP_MACOSX
 #include "nsILocalFileMac.h"
 #include "nsCommandLineServiceMac.h"
 #include "MacLaunchHelper.h"
 #endif
 
 #if defined(XP_WIN)
@@ -41,16 +43,18 @@
 #elif defined(XP_OS2)
 # include <unistd.h>
 # define INCL_DOSFILEMGR
 # include <os2.h>
 #elif defined(XP_UNIX)
 # include <unistd.h>
 #endif
 
+using namespace mozilla;
+
 //
 // We use execv to spawn the updater process on all UNIX systems except Mac OSX
 // since it is known to cause problems on the Mac.  Windows has execv, but it
 // is a faked implementation that doesn't really replace the current process.
 // Instead it spawns a new process, so we gain nothing from using execv on
 // Windows.
 //
 // On platforms where we are not calling execv, we may need to make the
@@ -84,18 +88,30 @@ static const char kUpdaterINI[] = "updat
 #ifdef XP_MACOSX
 static const char kUpdaterApp[] = "updater.app";
 #endif
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
 static const char kUpdaterPNG[] = "updater.png";
 #endif
 
 #if defined(MOZ_WIDGET_GONK)
+#include <linux/ioprio.h>
+
 static const int kB2GServiceArgc = 2;
 static const char *kB2GServiceArgv[] = { "/system/bin/start", "b2g" };
+
+static const char kAppUpdaterPrio[]        = "app.update.updater.prio";
+static const char kAppUpdaterOomScoreAdj[] = "app.update.updater.oom_score_adj";
+static const char kAppUpdaterIOPrioClass[] = "app.update.updater.ioprio.class";
+static const char kAppUpdaterIOPrioLevel[] = "app.update.updater.ioprio.level";
+
+static const int  kAppUpdaterPrioDefault        = 19;     // -20..19 where 19 = lowest priority
+static const int  kAppUpdaterOomScoreAdjDefault = -1000;  // -1000 = Never kill
+static const int  kAppUpdaterIOPrioClassDefault = IOPRIO_CLASS_IDLE;
+static const int  kAppUpdaterIOPrioLevelDefault = 0;      // Doesn't matter for CLASS IDLE
 #endif
 
 static nsresult
 GetCurrentWorkingDir(char *buf, size_t size)
 {
   // Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
   // This code is duplicated from xpcom/io/SpecialSystemDirectory.cpp:
 
@@ -563,18 +579,18 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIF
 static nsresult
 GetOSApplyToDir(nsACString& applyToDir)
 {
   nsCOMPtr<nsIProperties> ds =
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   NS_ASSERTION(ds, "Can't get directory service");
 
   nsCOMPtr<nsIFile> osApplyToDir;
-  nsresult rv = ds->Get(XRE_OS_UPDATE_APPLY_TO_DIR, NS_GET_IID(nsIFile),
-                        getter_AddRefs(osApplyToDir));
+  DebugOnly<nsresult> rv = ds->Get(XRE_OS_UPDATE_APPLY_TO_DIR, NS_GET_IID(nsIFile),
+                                   getter_AddRefs(osApplyToDir));
   NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the OS applyTo dir");
 
   return osApplyToDir->GetNativePath(applyToDir);
 }
 
 static void
 SetOSApplyToDir(nsIUpdate* update, const nsACString& osApplyToDir)
 {
@@ -802,16 +818,33 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
 
   if (gSafeMode) {
     PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
   }
 
   if (isOSUpdate) {
     PR_SetEnv("MOZ_OS_UPDATE=1");
   }
+#if defined(MOZ_WIDGET_GONK)
+  // We want the updater to be CPU friendly and not subject to being killed by
+  // the low memory killer, so we pass in some preferences to allow it to
+  // adjust its priority.
+
+  int32_t prioVal = Preferences::GetInt(kAppUpdaterPrio,
+                                        kAppUpdaterPrioDefault);
+  int32_t oomScoreAdj = Preferences::GetInt(kAppUpdaterOomScoreAdj,
+                                            kAppUpdaterOomScoreAdjDefault);
+  int32_t ioprioClass = Preferences::GetInt(kAppUpdaterIOPrioClass,
+                                            kAppUpdaterIOPrioClassDefault);
+  int32_t ioprioLevel = Preferences::GetInt(kAppUpdaterIOPrioLevel,
+                                            kAppUpdaterIOPrioLevelDefault);
+  nsPrintfCString prioEnv("MOZ_UPDATER_PRIO=%d/%d/%d/%d",
+                          prioVal, oomScoreAdj, ioprioClass, ioprioLevel);
+  PR_SetEnv(prioEnv.get());
+#endif
 
   LOG(("spawning updater process [%s]\n", updaterPath.get()));
 
 #if defined(USE_EXECV)
   // Don't use execv for background updates.
   if (restart) {
     execv(updaterPath.get(), argv);
   } else {