Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7830d595 authored by Keun-young Park's avatar Keun-young Park
Browse files

add shutdown animation

- Run shutdown animation during shutdown if surfaceflinger is
  available / running.
- services necessary for animation should be added to animation
  class.
- Keep debugging tools while non-critical services are terminated:
  logd, adbd, tombstoned

bug: 36526187
Test: many reboots

Change-Id: I758f700a622c6005f3df9f29de2b55270055ad4d
parent bc9cb388
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -198,6 +198,13 @@ runs the service.
  is in the class "default" if one is not specified via the
  class option. Additional classnames beyond the (required) first
  one are used to group services.
`animation class`
> 'animation' class should include all services necessary for both
  boot animation and shutdown animation. As these services can be
  launched very early during bootup and can run until the last stage
  of shutdown, access to /data partition is not guaranteed. These
  services can check files under /data but it should not keep files opened
  and should work when /data is not available.

`onrestart`
> Execute a Command (see below) when service restarts.
+35 −18
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <sys/wait.h>

#include <memory>
#include <set>
#include <string>
#include <thread>
#include <vector>
@@ -41,6 +42,7 @@
#include <logwrap/logwrap.h>

#include "log.h"
#include "property_service.h"
#include "reboot.h"
#include "service.h"
#include "util.h"
@@ -248,8 +250,9 @@ static bool UmountPartitions(std::vector<MountEntry>* partitions, int maxRetry,
                                              flags);
                } else {
                    umountDone = false;
                    PLOG(WARNING) << StringPrintf("cannot umount %s, flags:0x%x",
                                                  entry.mnt_fsname().c_str(), flags);
                    PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
                                                  entry.mnt_fsname().c_str(),
                                                  entry.mnt_dir().c_str(), flags);
                }
            }
        }
@@ -351,26 +354,40 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
    }
    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;

    static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
    for (const char* name : shutdown_critical_services) {
        Service* s = ServiceManager::GetInstance().FindServiceByName(name);
        if (s == nullptr) {
            LOG(WARNING) << "Shutdown critical service not found:" << name;
            continue;
        }
        s->Start();  // make sure that it is running.
    // keep debugging tools until non critical ones are all gone.
    const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
    // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
    const std::set<std::string> to_starts{"watchdogd", "vold"};
    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
        if (kill_after_apps.count(s->name())) {
            s->SetShutdownCritical();
        } else if (to_starts.count(s->name())) {
            s->Start();
            s->SetShutdownCritical();
        }
    });

    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
        property_set("service.bootanim.exit", "0");
        // Could be in the middle of animation. Stop and start so that it can pick
        // up the right mode.
        bootAnim->Stop();
        // start all animation classes if stopped.
        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
            s->Start();
            s->SetShutdownCritical();  // will not check animation class separately
        });
        bootAnim->Start();
        surfaceFlinger->SetShutdownCritical();
        bootAnim->SetShutdownCritical();
    }

    // optional shutdown step
    // 1. terminate all services except shutdown critical ones. wait for delay to finish
    if (shutdownTimeout > 0) {
        LOG(INFO) << "terminating init services";
        // tombstoned can write to data when other services are killed. so finish it first.
        static const constexpr char* first_to_kill[] = {"tombstoned"};
        for (const char* name : first_to_kill) {
            Service* s = ServiceManager::GetInstance().FindServiceByName(name);
            if (s != nullptr) s->Stop();
        }

        // Ask all services to terminate except shutdown critical ones.
        ServiceManager::GetInstance().ForEachService([](Service* s) {
@@ -409,8 +426,8 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re

    // minimum safety steps before restarting
    // 2. kill all services except ones that are necessary for the shutdown sequence.
    ServiceManager::GetInstance().ForEachService([](Service* s) {
        if (!s->IsShutdownCritical()) s->Stop();
    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
        if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
    });
    ServiceManager::GetInstance().ReapAnyOutstandingChildren();