xref: /aosp_15_r20/system/core/init/reboot_test.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "reboot.h"
18 
19 #include <errno.h>
20 #include <unistd.h>
21 
22 #include <memory>
23 #include <string_view>
24 
25 #include <android-base/file.h>
26 #include <android-base/properties.h>
27 #include <android-base/strings.h>
28 #include <gtest/gtest.h>
29 #include <selinux/selinux.h>
30 
31 #include "builtin_arguments.h"
32 #include "builtins.h"
33 #include "parser.h"
34 #include "service_list.h"
35 #include "service_parser.h"
36 #include "subcontext.h"
37 #include "util.h"
38 
39 using namespace std::literals;
40 
41 using android::base::GetProperty;
42 using android::base::Join;
43 using android::base::SetProperty;
44 using android::base::Split;
45 using android::base::StringReplace;
46 using android::base::WaitForProperty;
47 using android::base::WriteStringToFd;
48 
49 namespace android {
50 namespace init {
51 
52 class RebootTest : public ::testing::Test {
53   public:
RebootTest()54     RebootTest() {
55         std::vector<std::string> names = GetServiceNames();
56         if (!names.empty()) {
57             ADD_FAILURE() << "Expected empty ServiceList but found: [" << Join(names, ',') << "]";
58         }
59     }
60 
~RebootTest()61     ~RebootTest() {
62         std::vector<std::string> names = GetServiceNames();
63         for (const auto& name : names) {
64             auto s = ServiceList::GetInstance().FindService(name);
65             auto pid = s->pid();
66             ServiceList::GetInstance().RemoveService(*s);
67             if (pid > 0) {
68                 kill(pid, SIGTERM);
69                 kill(pid, SIGKILL);
70             }
71         }
72     }
73 
74   private:
GetServiceNames() const75     std::vector<std::string> GetServiceNames() const {
76         std::vector<std::string> names;
77         for (const auto& s : ServiceList::GetInstance()) {
78             names.push_back(s->name());
79         }
80         return names;
81     }
82 };
83 
GetSecurityContext()84 std::string GetSecurityContext() {
85     char* ctx;
86     if (getcon(&ctx) == -1) {
87         ADD_FAILURE() << "Failed to call getcon : " << strerror(errno);
88     }
89     std::string result = std::string(ctx);
90     freecon(ctx);
91     return result;
92 }
93 
AddTestService(const std::string & name)94 void AddTestService(const std::string& name) {
95     static constexpr std::string_view kScriptTemplate = R"init(
96 service $name /system/bin/yes
97     user shell
98     group shell
99     seclabel $selabel
100 )init";
101 
102     std::string script = StringReplace(StringReplace(kScriptTemplate, "$name", name, false),
103                                        "$selabel", GetSecurityContext(), false);
104     ServiceList& service_list = ServiceList::GetInstance();
105     Parser parser;
106     parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, nullptr));
107 
108     TemporaryFile tf;
109     ASSERT_TRUE(tf.fd != -1);
110     ASSERT_TRUE(WriteStringToFd(script, tf.fd));
111     ASSERT_TRUE(parser.ParseConfig(tf.path));
112 }
113 
TEST_F(RebootTest,StopServicesSIGTERM)114 TEST_F(RebootTest, StopServicesSIGTERM) {
115     if (getuid() != 0) {
116         GTEST_SKIP() << "Skipping test, must be run as root.";
117         return;
118     }
119 
120     AddTestService("A");
121     AddTestService("B");
122 
123     auto service_a = ServiceList::GetInstance().FindService("A");
124     ASSERT_NE(nullptr, service_a);
125     auto service_b = ServiceList::GetInstance().FindService("B");
126     ASSERT_NE(nullptr, service_b);
127 
128     ASSERT_RESULT_OK(service_a->Start());
129     ASSERT_TRUE(service_a->IsRunning());
130     ASSERT_RESULT_OK(service_b->Start());
131     ASSERT_TRUE(service_b->IsRunning());
132 
133     std::unique_ptr<Service> oneshot_service;
134     {
135         auto result = Service::MakeTemporaryOneshotService(
136                 {"exec", GetSecurityContext(), "--", "/system/bin/yes"});
137         ASSERT_RESULT_OK(result);
138         oneshot_service = std::move(*result);
139     }
140     std::string oneshot_service_name = oneshot_service->name();
141     oneshot_service->Start();
142     ASSERT_TRUE(oneshot_service->IsRunning());
143     ServiceList::GetInstance().AddService(std::move(oneshot_service));
144 
145     EXPECT_EQ(0, StopServicesAndLogViolations({"A", "B", oneshot_service_name}, 10s,
146                                               /* terminate= */ true));
147     EXPECT_FALSE(service_a->IsRunning());
148     EXPECT_FALSE(service_b->IsRunning());
149     // Oneshot services are deleted from the ServiceList after they are destroyed.
150     auto oneshot_service_after_stop = ServiceList::GetInstance().FindService(oneshot_service_name);
151     EXPECT_EQ(nullptr, oneshot_service_after_stop);
152 }
153 
TEST_F(RebootTest,StopServicesSIGKILL)154 TEST_F(RebootTest, StopServicesSIGKILL) {
155     if (getuid() != 0) {
156         GTEST_SKIP() << "Skipping test, must be run as root.";
157         return;
158     }
159 
160     AddTestService("A");
161     AddTestService("B");
162 
163     auto service_a = ServiceList::GetInstance().FindService("A");
164     ASSERT_NE(nullptr, service_a);
165     auto service_b = ServiceList::GetInstance().FindService("B");
166     ASSERT_NE(nullptr, service_b);
167 
168     ASSERT_RESULT_OK(service_a->Start());
169     ASSERT_TRUE(service_a->IsRunning());
170     ASSERT_RESULT_OK(service_b->Start());
171     ASSERT_TRUE(service_b->IsRunning());
172 
173     std::unique_ptr<Service> oneshot_service;
174     {
175         auto result = Service::MakeTemporaryOneshotService(
176                 {"exec", GetSecurityContext(), "--", "/system/bin/yes"});
177         ASSERT_RESULT_OK(result);
178         oneshot_service = std::move(*result);
179     }
180     std::string oneshot_service_name = oneshot_service->name();
181     oneshot_service->Start();
182     ASSERT_TRUE(oneshot_service->IsRunning());
183     ServiceList::GetInstance().AddService(std::move(oneshot_service));
184 
185     EXPECT_EQ(0, StopServicesAndLogViolations({"A", "B", oneshot_service_name}, 10s,
186                                               /* terminate= */ false));
187     EXPECT_FALSE(service_a->IsRunning());
188     EXPECT_FALSE(service_b->IsRunning());
189     // Oneshot services are deleted from the ServiceList after they are destroyed.
190     auto oneshot_service_after_stop = ServiceList::GetInstance().FindService(oneshot_service_name);
191     EXPECT_EQ(nullptr, oneshot_service_after_stop);
192 }
193 
194 }  // namespace init
195 }  // namespace android
196