blob: b3d038d14f74af7ea537a21dc299c82a81b803d6 [file] [log] [blame]
Nikita Ioffe660ffde2020-12-10 16:52:35 +00001/*
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
39using namespace std::literals;
40
41using android::base::GetProperty;
42using android::base::Join;
43using android::base::SetProperty;
44using android::base::Split;
45using android::base::StringReplace;
46using android::base::WaitForProperty;
47using android::base::WriteStringToFd;
48
49namespace android {
50namespace init {
51
52class RebootTest : public ::testing::Test {
53 public:
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
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:
75 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
84std::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
94void AddTestService(const std::string& name) {
95 static constexpr std::string_view kScriptTemplate = R"init(
96service $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",
107 std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
108
109 TemporaryFile tf;
110 ASSERT_TRUE(tf.fd != -1);
111 ASSERT_TRUE(WriteStringToFd(script, tf.fd));
112 ASSERT_TRUE(parser.ParseConfig(tf.path));
113}
114
115TEST_F(RebootTest, StopServicesSIGTERM) {
Nikita Ioffe49b3a5c2021-06-30 00:20:01 +0100116 if (getuid() != 0) {
117 GTEST_SKIP() << "Skipping test, must be run as root.";
118 return;
119 }
120
Nikita Ioffe660ffde2020-12-10 16:52:35 +0000121 AddTestService("A");
122 AddTestService("B");
123
124 auto service_a = ServiceList::GetInstance().FindService("A");
125 ASSERT_NE(nullptr, service_a);
126 auto service_b = ServiceList::GetInstance().FindService("B");
127 ASSERT_NE(nullptr, service_b);
128
129 ASSERT_RESULT_OK(service_a->Start());
130 ASSERT_TRUE(service_a->IsRunning());
131 ASSERT_RESULT_OK(service_b->Start());
132 ASSERT_TRUE(service_b->IsRunning());
133
134 std::unique_ptr<Service> oneshot_service;
135 {
136 auto result = Service::MakeTemporaryOneshotService(
137 {"exec", GetSecurityContext(), "--", "/system/bin/yes"});
138 ASSERT_RESULT_OK(result);
139 oneshot_service = std::move(*result);
140 }
141 std::string oneshot_service_name = oneshot_service->name();
142 oneshot_service->Start();
143 ASSERT_TRUE(oneshot_service->IsRunning());
144 ServiceList::GetInstance().AddService(std::move(oneshot_service));
145
146 EXPECT_EQ(0, StopServicesAndLogViolations({"A", "B", oneshot_service_name}, 10s,
147 /* terminate= */ true));
148 EXPECT_FALSE(service_a->IsRunning());
149 EXPECT_FALSE(service_b->IsRunning());
150 // Oneshot services are deleted from the ServiceList after they are destroyed.
151 auto oneshot_service_after_stop = ServiceList::GetInstance().FindService(oneshot_service_name);
152 EXPECT_EQ(nullptr, oneshot_service_after_stop);
153}
154
155TEST_F(RebootTest, StopServicesSIGKILL) {
Nikita Ioffe49b3a5c2021-06-30 00:20:01 +0100156 if (getuid() != 0) {
157 GTEST_SKIP() << "Skipping test, must be run as root.";
158 return;
159 }
160
Nikita Ioffe660ffde2020-12-10 16:52:35 +0000161 AddTestService("A");
162 AddTestService("B");
163
164 auto service_a = ServiceList::GetInstance().FindService("A");
165 ASSERT_NE(nullptr, service_a);
166 auto service_b = ServiceList::GetInstance().FindService("B");
167 ASSERT_NE(nullptr, service_b);
168
169 ASSERT_RESULT_OK(service_a->Start());
170 ASSERT_TRUE(service_a->IsRunning());
171 ASSERT_RESULT_OK(service_b->Start());
172 ASSERT_TRUE(service_b->IsRunning());
173
174 std::unique_ptr<Service> oneshot_service;
175 {
176 auto result = Service::MakeTemporaryOneshotService(
177 {"exec", GetSecurityContext(), "--", "/system/bin/yes"});
178 ASSERT_RESULT_OK(result);
179 oneshot_service = std::move(*result);
180 }
181 std::string oneshot_service_name = oneshot_service->name();
182 oneshot_service->Start();
183 ASSERT_TRUE(oneshot_service->IsRunning());
184 ServiceList::GetInstance().AddService(std::move(oneshot_service));
185
186 EXPECT_EQ(0, StopServicesAndLogViolations({"A", "B", oneshot_service_name}, 10s,
187 /* terminate= */ false));
188 EXPECT_FALSE(service_a->IsRunning());
189 EXPECT_FALSE(service_b->IsRunning());
190 // Oneshot services are deleted from the ServiceList after they are destroyed.
191 auto oneshot_service_after_stop = ServiceList::GetInstance().FindService(oneshot_service_name);
192 EXPECT_EQ(nullptr, oneshot_service_after_stop);
193}
194
195} // namespace init
196} // namespace android