DRTVWR-474: Do NOT autokill updater process on viewer termination.
The updater is required to survive beyond termination of the viewer that launched it so it can launch the next installer, or a replacement viewer. Having the old viewer forcibly terminate it on shutdown would be counter- productive. Introduce a third LLLeap::create() overload taking LLProcess::Params, which gives access to autokill, cwd and other options previously unsupported by LLLeap. Reimplement the existing create() overloads in terms of this new one, since LLLeapImpl::LLLeapImpl() is already based on LLProcess::Params anyway. Use LLProcess::Params in LLAppViewer::init() to specify the updater process, setting autokill=false. Refactoring LLLeapImpl() apparently involved engaging an LLInitParam::Block feature never before used: had to drag operator() into Multiple from its base class TypedParam (as has been done in other TypedParam subclasses).master
parent
6e1b2e137e
commit
b1955d4247
|
|
@ -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)
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -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 @@ public:
|
|||
// 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 @@ public:
|
|||
// 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 @@ public:
|
|||
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 @@ private:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "llinstancetracker.h"
|
||||
#include "llexception.h"
|
||||
#include "llprocess.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -61,6 +62,19 @@ public:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
Loading…
Reference in New Issue