46
51
return !instances().empty();
54
/** Function to create all the standard environment variables that we're
55
building for everyone. Mostly stuff involving paths.
57
\param package Name of the package
58
\param pkgdir Directory that the package lives in
60
std::list<std::pair<std::string, std::string>> Base::confinedEnv(const std::string& package, const std::string& pkgdir)
62
std::list<std::pair<std::string, std::string>> retval{{"UBUNTU_APPLICATION_ISOLATION", "1"}};
64
/* C Funcs can return null, which offends std::string */
65
auto cset = [&retval](const gchar* key, const gchar* value) {
68
g_debug("Setting '%s' to '%s'", key, value);
69
retval.emplace_back(std::make_pair(key, value));
73
cset("XDG_CACHE_HOME", g_get_user_cache_dir());
74
cset("XDG_CONFIG_HOME", g_get_user_config_dir());
75
cset("XDG_DATA_HOME", g_get_user_data_dir());
76
cset("XDG_RUNTIME_DIR", g_get_user_runtime_dir());
78
/* Add the application's dir to the list of sources for data */
79
gchar* basedatadirs = g_strjoinv(":", (gchar**)g_get_system_data_dirs());
80
gchar* datadirs = g_strjoin(":", pkgdir.c_str(), basedatadirs, nullptr);
81
cset("XDG_DATA_DIRS", datadirs);
85
/* Set TMPDIR to something sane and application-specific */
86
gchar* tmpdir = g_strdup_printf("%s/confined/%s", g_get_user_runtime_dir(), package.c_str());
87
cset("TMPDIR", tmpdir);
88
g_debug("Creating '%s'", tmpdir);
89
g_mkdir_with_parents(tmpdir, 0700);
92
/* Do the same for nvidia */
93
gchar* nv_shader_cachedir = g_strdup_printf("%s/%s", g_get_user_cache_dir(), package.c_str());
94
cset("__GL_SHADER_DISK_CACHE_PATH", nv_shader_cachedir);
95
g_free(nv_shader_cachedir);
100
/** Checks to see if we have a primary PID for the instance */
49
101
bool UpstartInstance::isRunning()
51
103
return primaryPid() != 0;
106
/** Uses Upstart to get the primary PID of the instance using Upstart's
54
108
pid_t UpstartInstance::primaryPid()
56
110
auto jobpath = registry_->impl->upstartJobPath(job_);
207
275
pidListToDbus(pids, "ApplicationResumed");
278
/** Stops this instance by asking Upstart to stop it. Upstart will then
279
send a SIGTERM and five seconds later start killing things. */
210
280
void UpstartInstance::stop()
212
ubuntu_app_launch_stop_application(std::string(appId_).c_str());
282
if (!registry_->impl->thread.executeOnThread<bool>([this]() {
284
g_debug("Stopping job %s app_id %s instance_id %s", job_.c_str(), std::string(appId_).c_str(),
287
auto jobpath = registry_->impl->upstartJobPath(job_);
290
throw new std::runtime_error("Unable to get job path for Upstart job '" + job_ + "'");
293
GVariantBuilder builder;
294
g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
295
g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
297
g_variant_builder_add_value(
298
&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", std::string(appId_).c_str())));
300
if (!instance_.empty())
302
g_variant_builder_add_value(
303
&builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instance_.c_str())));
306
g_variant_builder_close(&builder);
307
g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
309
GError* error = nullptr;
310
GVariant* stop_variant =
311
g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* Dbus */
312
DBUS_SERVICE_UPSTART, /* Upstart name */
313
jobpath.c_str(), /* path */
314
DBUS_INTERFACE_UPSTART_JOB, /* interface */
316
g_variant_builder_end(&builder), /* params */
317
nullptr, /* return */
318
G_DBUS_CALL_FLAGS_NONE, /* flags */
319
-1, /* timeout: default */
320
registry_->impl->thread.getCancellable().get(), /* cancellable */
321
&error); /* error (hopefully not) */
323
g_clear_pointer(&stop_variant, g_variant_unref);
325
if (error != nullptr)
327
g_warning("Unable to stop job %s app_id %s instance_id %s: %s", job_.c_str(),
328
std::string(appId_).c_str(), instance_.c_str(), error->message);
336
g_warning("Unable to stop Upstart instance");
215
340
/** Sets the OOM adjustment by getting the list of PIDs and writing
216
the value to each of their files in proc */
341
the value to each of their files in proc
343
\param score OOM Score to set
217
345
void UpstartInstance::setOomAdjustment(const oom::Score score)
219
347
forAllPids([this, &score](pid_t pid) { oomValueToPid(pid, score); });
481
647
for (auto url : urls)
483
649
auto str = g_strdup(url.value().c_str());
650
g_debug("Converting URL: %s", str);
484
651
g_array_append_val(array, str);
487
654
return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev);
490
std::shared_ptr<UpstartInstance> UpstartInstance::launch(const AppID& appId,
491
const std::string& job,
492
const std::string& instance,
493
const std::vector<Application::URL>& urls,
494
const std::shared_ptr<Registry>& registry,
497
auto urlstrv = urlsToStrv(urls);
498
auto start_result = registry->impl->thread.executeOnThread<gboolean>([registry, &appId, &urlstrv, &mode]() {
499
return start_application_core(registry->impl->_dbus.get(), registry->impl->thread.getCancellable().get(),
500
std::string(appId).c_str(), urlstrv.get(),
501
mode == launchMode::STANDARD ? FALSE : TRUE);
504
if (start_result == FALSE)
657
/** Small helper that we can new/delete to work better with C stuff */
660
std::shared_ptr<UpstartInstance> ptr;
663
/** Callback from starting an application. It checks to see whether the
664
app is already running. If it is already running then we need to send
665
the URLs to it via DBus.
667
\param obj The GDBusConnection object
668
\param res Async result object
669
\param user_data A pointer to a StartCHelper structure
671
void UpstartInstance::application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data)
673
auto data = static_cast<StartCHelper*>(user_data);
674
GError* error{nullptr};
675
GVariant* result{nullptr};
677
tracepoint(ubuntu_app_launch, libual_start_message_callback, std::string(data->ptr->appId_).c_str());
679
g_debug("Started Message Callback: %s", std::string(data->ptr->appId_).c_str());
681
result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
683
g_clear_pointer(&result, g_variant_unref);
685
if (error != nullptr)
687
if (g_dbus_error_is_remote_error(error))
689
gchar* remote_error = g_dbus_error_get_remote_error(error);
690
g_debug("Remote error: %s", remote_error);
691
if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0)
693
auto urls = urlsToStrv(data->ptr->urls_);
694
second_exec(data->ptr->registry_->impl->_dbus.get(), /* DBus */
695
data->ptr->registry_->impl->thread.getCancellable().get(), /* cancellable */
696
data->ptr->primaryPid(), /* primary pid */
697
std::string(data->ptr->appId_).c_str(), /* appid */
698
urls.get()); /* urls */
701
g_free(remote_error);
705
g_warning("Unable to emit event to start application: %s", error->message);
713
/** Launch an application and create a new UpstartInstance object to track
716
\param appId Application ID
717
\param job Upstart job name
718
\param instance Upstart instance name
719
\param urls URLs sent to the application (only on launch today)
720
\param registry Registry of persistent connections to use
721
\param mode Whether or not to setup the environment for testing
722
\param getenv A function to get additional environment variable when appropriate
724
std::shared_ptr<UpstartInstance> UpstartInstance::launch(
726
const std::string& job,
727
const std::string& instance,
728
const std::vector<Application::URL>& urls,
729
const std::shared_ptr<Registry>& registry,
731
std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv)
509
return std::make_shared<UpstartInstance>(appId, job, instance, registry);
736
return registry->impl->thread.executeOnThread<std::shared_ptr<UpstartInstance>>(
737
[&]() -> std::shared_ptr<UpstartInstance> {
738
std::string appIdStr{appId};
739
g_debug("Initializing params for an new UpstartInstance for: %s", appIdStr.c_str());
741
tracepoint(ubuntu_app_launch, libual_start, appIdStr.c_str());
744
if (ubuntu::app_launch::Registry::Impl::isWatchingAppStarting())
749
auto handshake = starting_handshake_start(appIdStr.c_str(), timeout);
750
if (handshake == nullptr)
752
g_warning("Unable to setup starting handshake");
755
/* Figure out the DBus path for the job */
756
auto jobpath = registry->impl->upstartJobPath(job);
758
/* Build up our environment */
761
env.emplace_back(std::make_pair("APP_ID", appIdStr)); /* Application ID */
762
env.emplace_back(std::make_pair("APP_LAUNCHER_PID", std::to_string(getpid()))); /* Who we are, for bugs */
766
auto accumfunc = [](const std::string& prev, Application::URL thisurl) -> std::string {
767
gchar* gescaped = g_shell_quote(thisurl.value().c_str());
769
if (gescaped != nullptr)
776
g_warning("Unable to escape URL: %s", thisurl.value().c_str());
786
return prev + " " + escaped;
789
auto urlstring = std::accumulate(urls.begin(), urls.end(), std::string{}, accumfunc);
790
env.emplace_back(std::make_pair("APP_URIS", urlstring));
793
if (mode == launchMode::TEST)
795
env.emplace_back(std::make_pair("QT_LOAD_TESTABILITY", "1"));
798
/* Convert to GVariant */
799
GVariantBuilder builder;
800
g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
802
g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
804
for (const auto& envvar : env)
806
g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf(
807
"%s=%s", envvar.first.c_str(), envvar.second.c_str())));
810
g_variant_builder_close(&builder);
811
g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
813
auto retval = std::make_shared<UpstartInstance>(appId, job, instance, urls, registry);
814
auto chelper = new StartCHelper{};
815
chelper->ptr = retval;
817
tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str());
818
starting_handshake_wait(handshake);
819
tracepoint(ubuntu_app_launch, handshake_complete, appIdStr.c_str());
821
/* Call the job start function */
822
g_debug("Asking Upstart to start task for: %s", appIdStr.c_str());
823
g_dbus_connection_call(registry->impl->_dbus.get(), /* bus */
824
DBUS_SERVICE_UPSTART, /* service name */
825
jobpath.c_str(), /* Path */
826
DBUS_INTERFACE_UPSTART_JOB, /* interface */
827
"Start", /* method */
828
g_variant_builder_end(&builder), /* params */
829
nullptr, /* return */
830
G_DBUS_CALL_FLAGS_NONE, /* flags */
831
-1, /* default timeout */
832
registry->impl->thread.getCancellable().get(), /* cancellable */
833
application_start_cb, /* callback */
837
tracepoint(ubuntu_app_launch, libual_start_message_sent, appIdStr.c_str());
512
843
} // namespace app_impls