X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fsrc%2Fanbox%2Fcmds%2Flaunch.cpp;fp=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fsrc%2Fanbox%2Fcmds%2Flaunch.cpp;h=a8de408e65c922f93f8506067e6e7bc7824063ad;hb=e26c1ec581be598521517829adba8c8dd23a768f;hp=0000000000000000000000000000000000000000;hpb=6699c1aea74eeb0eb400e6299079f0c7576f716f;p=iec.git diff --git a/src/type3_AndroidCloud/anbox-master/src/anbox/cmds/launch.cpp b/src/type3_AndroidCloud/anbox-master/src/anbox/cmds/launch.cpp new file mode 100644 index 0000000..a8de408 --- /dev/null +++ b/src/type3_AndroidCloud/anbox-master/src/anbox/cmds/launch.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/cmds/launch.h" +#include "anbox/dbus/stub/application_manager.h" +#include "anbox/dbus/interface.h" +#include "anbox/ui/splash_screen.h" +#include "anbox/system_configuration.h" +#include "anbox/logger.h" + +#include "core/posix/exec.h" +#include "core/posix/fork.h" +#include "core/posix/signal.h" + +#include + +#include +#include + +namespace fs = boost::filesystem; + +namespace { +constexpr unsigned int max_session_mgr_wait_attempts{10}; +const std::chrono::seconds session_mgr_wait_interval{5}; +constexpr unsigned int max_dbus_service_wait_attempts{10}; +const std::chrono::seconds dbus_service_wait_interval{5}; + +static int redirect_to_null(int flags, int fd) { + int fd2; + if ((fd2 = open("/dev/null", flags)) < 0) + return -1; + + if (fd2 == fd) + return fd; + + if (dup2(fd2, fd) < 0) + return -1; + + close(fd2); + return fd; +} +} // namespace + +bool anbox::cmds::Launch::launch_session_manager() { + std::vector args = {"session-manager"}; + const auto should_force_software_rendering = utils::get_env_value("ANBOX_FORCE_SOFTWARE_RENDERING", "false"); + if (should_force_software_rendering == "true") + args.push_back("--software-rendering"); + + std::map env; + core::posix::this_process::env::for_each([&](const std::string &name, const std::string &value) { + env.insert({name, value}); + }); + + const auto exe_path = utils::process_get_exe_path(::getpid()); + if (!fs::exists(exe_path)) { + ERROR("Can't find correct anbox executable to run. Found %s but does not exist", exe_path); + return false; + } + + try { + auto flags = core::posix::StandardStream::empty; + auto child = core::posix::fork([&]() { + + // We redirect all in/out/err to /dev/null as they can't be seen + // anywhere. All logging output will directly go to syslog as we + // will become a session leader below which will get us rid of a + // controlling terminal. + if (redirect_to_null(O_RDONLY, 0) < 0 || + redirect_to_null(O_WRONLY, 1) < 0 || + redirect_to_null(O_WRONLY, 2) < 0) { + ERROR("Failed to redirect stdout/stderr/stdin: %s", strerror(errno)); + return core::posix::exit::Status::failure; + } + + // As we forked one time already we're sure that our process is + // not the session leader anymore so we can safely become the + // new one and lead the process group. + if (setsid() < 0) { + ERROR("Failed to become new session leader: %s", strerror(errno)); + return core::posix::exit::Status::failure; + } + + umask(0077); + + if (chdir("/") < 0) { + ERROR("Failed to change current directory: %s", strerror(errno)); + return core::posix::exit::Status::failure; + } + + auto grandchild = core::posix::exec(exe_path, args, env, flags); + grandchild.dont_kill_on_cleanup(); + return core::posix::exit::Status::success; + }, flags); + + // We don't wait for the grandchild but the child as we use double forking + // here to break through the process hierarchy and make the grandchild a + // direct child of the init process so it keeps running on its own and + // indepent of our short living process here. + child.wait_for(core::posix::wait::Flags::untraced); + + DEBUG("Started session manager, will now try to connect .."); + } + catch (...) { + ERROR("Failed to start session manager instance"); + } + + return true; +} + +bool anbox::cmds::Launch::try_launch_activity(const std::shared_ptr &stub) { + try { + DEBUG("Sending launch intent %s to Android ..", intent_); + stub->launch(intent_, graphics::Rect::Invalid, stack_); + } catch (const std::exception &err) { + ERROR("Failed to launch activity: %s", err.what()); + return false; + } catch (...) { + ERROR("Failed to launch activity"); + return false; + } + + return true; +} + +anbox::cmds::Launch::Launch() + : CommandWithFlagsAndAction{ + cli::Name{"launch"}, cli::Usage{"launch"}, + cli::Description{"Launch an Activity by sending an intent"}} { + flag(cli::make_flag(cli::Name{"action"}, + cli::Description{"Action of the intent"}, + intent_.action)); + flag(cli::make_flag(cli::Name{"type"}, + cli::Description{"MIME type for the intent"}, + intent_.type)); + flag(cli::make_flag(cli::Name{"uri"}, + cli::Description{"URI used as data within the intent"}, + intent_.uri)); + flag(cli::make_flag(cli::Name{"package"}, + cli::Description{"Package the intent should go to"}, + intent_.package)); + flag(cli::make_flag(cli::Name{"component"}, + cli::Description{"Component of a package the intent should go"}, + intent_.component)); + flag(cli::make_flag(cli::Name{"stack"}, + cli::Description{"Which window stack the activity should be started on. Possible: default, fullscreen, freeform"}, + stack_)); + flag(cli::make_flag(cli::Name{"use-system-dbus"}, + cli::Description{"Use system instead of session DBus"}, + use_system_dbus_)); + + + action([this](const cli::Command::Context&) { + if (!intent_.valid()) { + ERROR("The intent you provided is invalid. Please provide a correct launch intent."); + ERROR("For example to launch the application manager, run:"); + ERROR("$ anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity"); + return EXIT_FAILURE; + } + + auto bus_type = anbox::dbus::Bus::Type::Session; + if (use_system_dbus_) + bus_type = anbox::dbus::Bus::Type::System; + auto bus = std::make_shared(bus_type); + + std::shared_ptr ss; + if (!bus->has_service_with_name(dbus::interface::Service::name())) { + DEBUG("Session manager is not yet running, trying to start it"); + + if (!launch_session_manager()) + return EXIT_FAILURE; + + // Give us a splash screen as long as we're trying to connect + // with the session manager so the user knows something is + // happening after he started Anbox. + ss = std::make_shared(); + } + + unsigned int n = 0; + while (n < max_dbus_service_wait_attempts) { + if (bus->has_service_with_name(dbus::interface::Service::name())) + break; + + std::this_thread::sleep_for(dbus_service_wait_interval); + n++; + } + + auto app_mgr = dbus::stub::ApplicationManager::create_for_bus(bus); + n = 0; + while (n < max_session_mgr_wait_attempts) { + app_mgr->update_properties(); + if (app_mgr->ready().get()) + break; + + std::this_thread::sleep_for(session_mgr_wait_interval); + n++; + } + + if (!app_mgr->ready()) { + ERROR("Session manager failed to become ready"); + return EXIT_FAILURE; + } + + // If we have a splash screen now is the time to drop it as we're + // going to launch the real application now. + ss.reset(); + + const auto success = try_launch_activity(app_mgr); + return success ? EXIT_SUCCESS : EXIT_FAILURE; + }); +}