diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index f1f4226c409612b578803c7484ec817c03ae60da..7f5b9b4ac23e4e6afb5a236c034c0d82fc33b1a5 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -2115,6 +2115,9 @@ namespace LLInitParam
 			typedef typename super_t::iterator										iterator;
 			typedef typename super_t::const_iterator								const_iterator;
 
+			using super_t::operator();
+			using super_t::operator const container_t&;
+
 			explicit Multiple(const char* name = "")
 			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
 			{}
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index c87d2a3e588c87a6ee6a2e8a3dd808b1d540d116..cf8f8cc6a5ee9c8ca7c3168cbcc8f4ef6f69ed75 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -47,9 +47,9 @@ class LLLeapImpl: public LLLeap
     LOG_CLASS(LLLeap);
 public:
     // Called only by LLLeap::create()
-    LLLeapImpl(const std::string& desc, const std::vector<std::string>& plugin):
+    LLLeapImpl(const LLProcess::Params& cparams):
         // We might reassign mDesc in the constructor body if it's empty here.
-        mDesc(desc),
+        mDesc(cparams.desc),
         // We expect multiple LLLeapImpl instances. Definitely tweak
         // mDonePump's name for uniqueness.
         mDonePump("LLLeap", true),
@@ -67,17 +67,17 @@ class LLLeapImpl: public LLLeap
         // this class or method name.
         mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2)))
     {
-        // Rule out empty vector
-        if (plugin.empty())
+        // Rule out unpopulated Params block
+        if (! cparams.executable.isProvided())
         {
             LLTHROW(Error("no plugin command"));
         }
 
         // Don't leave desc empty either, but in this case, if we weren't
         // given one, we'll fake one.
-        if (desc.empty())
+        if (mDesc.empty())
         {
-            mDesc = LLProcess::basename(plugin[0]);
+            mDesc = LLProcess::basename(cparams.executable);
             // how about a toLower() variant that returns the transformed string?!
             std::string desclower(mDesc);
             LLStringUtil::toLower(desclower);
@@ -87,9 +87,9 @@ class LLLeapImpl: public LLLeap
             // notice Python specially: we provide Python LLSD serialization
             // support, so there's a pretty good reason to implement plugins
             // in that language.
-            if (plugin.size() >= 2 && (desclower == "python" || desclower == "python.exe"))
+            if (cparams.args.size() && (desclower == "python" || desclower == "python.exe"))
             {
-                mDesc = LLProcess::basename(plugin[1]);
+                mDesc = LLProcess::basename(cparams.args()[0]);
             }
         }
 
@@ -97,14 +97,10 @@ class LLLeapImpl: public LLLeap
         mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1));
 
         // Okay, launch child.
-        LLProcess::Params params;
+        // Get a modifiable copy of params block to set files and postend.
+        LLProcess::Params params(cparams);
+        // copy our deduced mDesc back into the params block
         params.desc = mDesc;
-        std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end());
-        params.executable = *pi++;
-        for ( ; pi != pend; ++pi)
-        {
-            params.args.add(*pi);
-        }
         params.files.add(LLProcess::FileParam("pipe")); // stdin
         params.files.add(LLProcess::FileParam("pipe")); // stdout
         params.files.add(LLProcess::FileParam("pipe")); // stderr
@@ -429,17 +425,17 @@ class LLLeapImpl: public LLLeap
     boost::scoped_ptr<LLLeapListener> mListener;
 };
 
-// This must follow the declaration of LLLeapImpl, so it may as well be last.
-LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc)
+// These must follow the declaration of LLLeapImpl, so they may as well be last.
+LLLeap* LLLeap::create(const LLProcess::Params& params, bool exc)
 {
     // If caller is willing to permit exceptions, just instantiate.
     if (exc)
-        return new LLLeapImpl(desc, plugin);
+        return new LLLeapImpl(params);
 
     // Caller insists on suppressing LLLeap::Error. Very well, catch it.
     try
     {
-        return new LLLeapImpl(desc, plugin);
+        return new LLLeapImpl(params);
     }
     catch (const LLLeap::Error&)
     {
@@ -447,6 +443,23 @@ LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>&
     }
 }
 
+LLLeap* LLLeap::create(const std::string& desc, const std::vector<std::string>& plugin, bool exc)
+{
+    LLProcess::Params params;
+    params.desc = desc;
+    std::vector<std::string>::const_iterator pi(plugin.begin()), pend(plugin.end());
+    // could validate here, but let's rely on LLLeapImpl's constructor
+    if (pi != pend)
+    {
+        params.executable = *pi++;
+    }
+    for ( ; pi != pend; ++pi)
+    {
+        params.args.add(*pi);
+    }
+    return create(params, exc);
+}
+
 LLLeap* LLLeap::create(const std::string& desc, const std::string& plugin, bool exc)
 {
     // Use LLStringUtil::getTokens() to parse the command line
diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h
index 8aac8a64c578e243f2ec74bbfaa434e7d301812c..7cecdf2f8f6821e4a7e0c844c60d92ef446c18ae 100644
--- a/indra/llcommon/llleap.h
+++ b/indra/llcommon/llleap.h
@@ -14,6 +14,7 @@
 
 #include "llinstancetracker.h"
 #include "llexception.h"
+#include "llprocess.h"
 #include <string>
 #include <vector>
 
@@ -61,6 +62,19 @@ class LL_COMMON_API LLLeap: public LLInstanceTracker<LLLeap>
     static LLLeap* create(const std::string& desc, const std::string& plugin,
                           bool exc=true);
 
+    /**
+     * Pass an LLProcess::Params instance to specify desc, executable, args et al.
+     *
+     * Note that files and postend are set implicitly; any values you set in
+     * those fields will be disregarded.
+     *
+     * Pass exc=false to suppress LLLeap::Error exception. Obviously in that
+     * case the caller cannot discover the nature of the error, merely that an
+     * error of some kind occurred (because create() returned NULL). Either
+     * way, the error is logged.
+     */
+    static LLLeap* create(const LLProcess::Params& params, bool exc=true);
+
     /**
      * Exception thrown for invalid create() arguments, e.g. no plugin
      * program. This is more resiliant than an LL_ERRS failure, because the
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 776fc85a2dbaf0818a1b935cbb8c940c93097950..bc4ce19f7726c8a84109dec900068bedeb204e79 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1130,30 +1130,35 @@ bool LLAppViewer::init()
 
 	gGLActive = FALSE;
 
-	std::vector<std::string> updater
+	LLProcess::Params updater;
+	updater.desc = "updater process";
+	// Because it's the updater, it MUST persist beyond the lifespan of the
+	// viewer itself.
+	updater.autokill = false;
 #if LL_WINDOWS
-		{ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater.exe") };
+	updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater.exe");
 #elif LL_DARWIN
 	// explicitly run the system Python interpreter on updater.py
-		{ "python", gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "updater.py") };
+	updater.executable = "python";
+	updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", "updater.py"));
 #else
-		{ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater") };
+	updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "updater");
 #endif
 	// add LEAP mode command-line argument to whichever of these we selected
-	updater.push_back("leap");
+	updater.args.add("leap");
 	// UpdaterServiceSettings
-	updater.push_back(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
+	updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
 	// channel
-	updater.push_back(LLVersionInfo::getChannel());
+	updater.args.add(LLVersionInfo::getChannel());
 	// testok
-	updater.push_back(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
+	updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
 	// UpdaterServiceURL
-	updater.push_back(gSavedSettings.getString("UpdaterServiceURL"));
+	updater.args.add(gSavedSettings.getString("UpdaterServiceURL"));
 	// ForceAddressSize
-	updater.push_back(stringize(gSavedSettings.getU32("ForceAddressSize")));
+	updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
 
 	// Run the updater. An exception from launching the updater should bother us.
-	LLLeap::create("updater process", updater, true);
+	LLLeap::create(updater, true);
 
 	// Iterate over --leap command-line options. But this is a bit tricky: if
 	// there's only one, it won't be an array at all.
@@ -3923,12 +3928,6 @@ void LLAppViewer::requestQuit()
 		gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
 	}
 
-	// Try to send last batch of avatar rez metrics.
-	if (!gDisconnected && isAgentAvatarValid())
-	{
-		gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
-	}
-
 	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
 	effectp->setPositionGlobal(gAgent.getPositionGlobal());
 	effectp->setColor(LLColor4U(gAgent.getEffectColor()));