| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2015 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 "service.h" | 
 | 18 |  | 
 | 19 | #include <fcntl.h> | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 20 | #include <inttypes.h> | 
| Mark Salyzyn | eca2507 | 2018-05-16 15:10:24 -0700 | [diff] [blame] | 21 | #include <linux/input.h> | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 22 | #include <linux/securebits.h> | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 23 | #include <sched.h> | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 24 | #include <sys/prctl.h> | 
| Vitalii Tomkiv | 081705c | 2016-05-18 17:36:30 -0700 | [diff] [blame] | 25 | #include <sys/resource.h> | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 26 | #include <sys/stat.h> | 
| Vitalii Tomkiv | 081705c | 2016-05-18 17:36:30 -0700 | [diff] [blame] | 27 | #include <sys/time.h> | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 28 | #include <termios.h> | 
| Dan Albert | af9ba4d | 2015-08-11 16:37:04 -0700 | [diff] [blame] | 29 | #include <unistd.h> | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 30 |  | 
| Elliott Hughes | 4f71319 | 2015-12-04 22:00:26 -0800 | [diff] [blame] | 31 | #include <android-base/file.h> | 
| Tom Cherry | 3f5eaae5 | 2017-04-06 16:30:22 -0700 | [diff] [blame] | 32 | #include <android-base/logging.h> | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 33 | #include <android-base/parseint.h> | 
| Elliott Hughes | dc80312 | 2018-05-24 18:00:39 -0700 | [diff] [blame] | 34 | #include <android-base/properties.h> | 
| Elliott Hughes | 4f71319 | 2015-12-04 22:00:26 -0800 | [diff] [blame] | 35 | #include <android-base/stringprintf.h> | 
| Elliott Hughes | f86b5a6 | 2016-06-24 15:12:21 -0700 | [diff] [blame] | 36 | #include <android-base/strings.h> | 
| Steven Moreland | e055d73 | 2017-10-05 18:50:22 -0700 | [diff] [blame] | 37 | #include <hidl-util/FQName.h> | 
| Tom Cherry | 3f5eaae5 | 2017-04-06 16:30:22 -0700 | [diff] [blame] | 38 | #include <processgroup/processgroup.h> | 
 | 39 | #include <selinux/selinux.h> | 
| Vitalii Tomkiv | 081705c | 2016-05-18 17:36:30 -0700 | [diff] [blame] | 40 | #include <system/thread_defs.h> | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 41 |  | 
| Tom Cherry | 7ac013d | 2017-08-25 10:39:25 -0700 | [diff] [blame] | 42 | #include "rlimit_parser.h" | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 43 | #include "util.h" | 
 | 44 |  | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 45 | #if defined(__ANDROID__) | 
| Jiyong Park | d7f7c20 | 2019-05-10 21:12:15 +0900 | [diff] [blame] | 46 | #include <ApexProperties.sysprop.h> | 
| Tom Cherry | 40acb37 | 2018-08-01 13:41:12 -0700 | [diff] [blame] | 47 | #include <android/api-level.h> | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 48 | #include <sys/system_properties.h> | 
 | 49 |  | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 50 | #include "init.h" | 
| Jiyong Park | 6866041 | 2019-01-16 23:00:59 +0900 | [diff] [blame] | 51 | #include "mount_namespace.h" | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 52 | #include "property_service.h" | 
| Tom Cherry | 40acb37 | 2018-08-01 13:41:12 -0700 | [diff] [blame] | 53 | #include "selinux.h" | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 54 | #else | 
 | 55 | #include "host_init_stubs.h" | 
 | 56 | #endif | 
 | 57 |  | 
| James Hawkins | e78ea77 | 2017-03-24 11:43:02 -0700 | [diff] [blame] | 58 | using android::base::boot_clock; | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 59 | using android::base::GetProperty; | 
 | 60 | using android::base::Join; | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 61 | using android::base::ParseInt; | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 62 | using android::base::Split; | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 63 | using android::base::StartsWith; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 64 | using android::base::StringPrintf; | 
 | 65 | using android::base::WriteStringToFile; | 
 | 66 |  | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 67 | namespace android { | 
 | 68 | namespace init { | 
 | 69 |  | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 70 | static Result<std::string> ComputeContextFromExecutable(const std::string& service_path) { | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 71 |     std::string computed_context; | 
 | 72 |  | 
 | 73 |     char* raw_con = nullptr; | 
 | 74 |     char* raw_filecon = nullptr; | 
 | 75 |  | 
 | 76 |     if (getcon(&raw_con) == -1) { | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 77 |         return Error() << "Could not get security context"; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 78 |     } | 
 | 79 |     std::unique_ptr<char> mycon(raw_con); | 
 | 80 |  | 
 | 81 |     if (getfilecon(service_path.c_str(), &raw_filecon) == -1) { | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 82 |         return Error() << "Could not get file context"; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 83 |     } | 
 | 84 |     std::unique_ptr<char> filecon(raw_filecon); | 
 | 85 |  | 
 | 86 |     char* new_con = nullptr; | 
 | 87 |     int rc = security_compute_create(mycon.get(), filecon.get(), | 
 | 88 |                                      string_to_security_class("process"), &new_con); | 
 | 89 |     if (rc == 0) { | 
 | 90 |         computed_context = new_con; | 
 | 91 |         free(new_con); | 
 | 92 |     } | 
 | 93 |     if (rc == 0 && computed_context == mycon.get()) { | 
| Nick Kralevich | 1ea19eb | 2017-08-25 12:08:57 -0700 | [diff] [blame] | 94 |         return Error() << "File " << service_path << "(labeled \"" << filecon.get() | 
 | 95 |                        << "\") has incorrect label or no domain transition from " << mycon.get() | 
 | 96 |                        << " to another SELinux domain defined. Have you configured your " | 
 | 97 |                           "service correctly? https://source.android.com/security/selinux/" | 
 | 98 |                           "device-policy#label_new_services_and_address_denials"; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 99 |     } | 
 | 100 |     if (rc < 0) { | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 101 |         return Error() << "Could not get process context"; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 102 |     } | 
 | 103 |     return computed_context; | 
 | 104 | } | 
 | 105 |  | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 106 | static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) { | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 107 |     std::vector<std::string> expanded_args; | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 108 |     std::vector<char*> c_strings; | 
 | 109 |  | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 110 |     expanded_args.resize(args.size()); | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 111 |     c_strings.push_back(const_cast<char*>(args[0].data())); | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 112 |     for (std::size_t i = 1; i < args.size(); ++i) { | 
 | 113 |         if (!expand_props(args[i], &expanded_args[i])) { | 
 | 114 |             LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'"; | 
 | 115 |         } | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 116 |         c_strings.push_back(expanded_args[i].data()); | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 117 |     } | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 118 |     c_strings.push_back(nullptr); | 
 | 119 |  | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 120 |     if (sigstop) { | 
 | 121 |         kill(getpid(), SIGSTOP); | 
 | 122 |     } | 
 | 123 |  | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 124 |     return execv(c_strings[0], c_strings.data()) == 0; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 125 | } | 
 | 126 |  | 
| Jiyong Park | 6866041 | 2019-01-16 23:00:59 +0900 | [diff] [blame] | 127 | static bool IsRuntimeApexReady() { | 
 | 128 |     struct stat buf; | 
 | 129 |     return stat("/apex/com.android.runtime/", &buf) == 0; | 
 | 130 | } | 
 | 131 |  | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 132 | unsigned long Service::next_start_order_ = 1; | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 133 | bool Service::is_exec_service_running_ = false; | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 134 |  | 
| Tom Cherry | cb0f9bb | 2017-09-12 15:58:47 -0700 | [diff] [blame] | 135 | Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands, | 
 | 136 |                  const std::vector<std::string>& args) | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 137 |     : Service(name, 0, 0, 0, {}, 0, "", subcontext_for_restart_commands, args) {} | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 138 |  | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 139 | Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 140 |                  const std::vector<gid_t>& supp_gids, unsigned namespace_flags, | 
 | 141 |                  const std::string& seclabel, Subcontext* subcontext_for_restart_commands, | 
 | 142 |                  const std::vector<std::string>& args) | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 143 |     : name_(name), | 
 | 144 |       classnames_({"default"}), | 
 | 145 |       flags_(flags), | 
 | 146 |       pid_(0), | 
 | 147 |       crash_count_(0), | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 148 |       proc_attr_{.ioprio_class = IoSchedClass_NONE, | 
 | 149 |                  .ioprio_pri = 0, | 
 | 150 |                  .uid = uid, | 
 | 151 |                  .gid = gid, | 
 | 152 |                  .supp_gids = supp_gids, | 
 | 153 |                  .priority = 0}, | 
 | 154 |       namespaces_{.flags = namespace_flags}, | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 155 |       seclabel_(seclabel), | 
| Tom Cherry | 9cbf570 | 2018-02-13 16:24:51 -0800 | [diff] [blame] | 156 |       onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0, | 
 | 157 |                  "onrestart", {}), | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 158 |       oom_score_adjust_(-1000), | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 159 |       start_order_(0), | 
| Tom Cherry | 9cbf570 | 2018-02-13 16:24:51 -0800 | [diff] [blame] | 160 |       args_(args) {} | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 161 |  | 
 | 162 | void Service::NotifyStateChange(const std::string& new_state) const { | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 163 |     if ((flags_ & SVC_TEMPORARY) != 0) { | 
 | 164 |         // Services created by 'exec' are temporary and don't have properties tracking their state. | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 165 |         return; | 
 | 166 |     } | 
 | 167 |  | 
| Tom Cherry | 1c3a53f | 2017-06-22 16:50:31 -0700 | [diff] [blame] | 168 |     std::string prop_name = "init.svc." + name_; | 
 | 169 |     property_set(prop_name, new_state); | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 170 |  | 
 | 171 |     if (new_state == "running") { | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 172 |         uint64_t start_ns = time_started_.time_since_epoch().count(); | 
| Tom Cherry | fed3373 | 2017-08-18 10:47:46 -0700 | [diff] [blame] | 173 |         std::string boottime_property = "ro.boottime." + name_; | 
 | 174 |         if (GetProperty(boottime_property, "").empty()) { | 
 | 175 |             property_set(boottime_property, std::to_string(start_ns)); | 
 | 176 |         } | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 177 |     } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 178 | } | 
 | 179 |  | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 180 | void Service::KillProcessGroup(int signal) { | 
| Tom Cherry | 33838b1 | 2017-05-04 11:32:36 -0700 | [diff] [blame] | 181 |     // If we've already seen a successful result from killProcessGroup*(), then we have removed | 
 | 182 |     // the cgroup already and calling these functions a second time will simply result in an error. | 
 | 183 |     // This is true regardless of which signal was sent. | 
 | 184 |     // These functions handle their own logging, so no additional logging is needed. | 
 | 185 |     if (!process_cgroup_empty_) { | 
 | 186 |         LOG(INFO) << "Sending signal " << signal << " to service '" << name_ << "' (pid " << pid_ | 
 | 187 |                   << ") process group..."; | 
 | 188 |         int r; | 
 | 189 |         if (signal == SIGTERM) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 190 |             r = killProcessGroupOnce(proc_attr_.uid, pid_, signal); | 
| Tom Cherry | 33838b1 | 2017-05-04 11:32:36 -0700 | [diff] [blame] | 191 |         } else { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 192 |             r = killProcessGroup(proc_attr_.uid, pid_, signal); | 
| Tom Cherry | 33838b1 | 2017-05-04 11:32:36 -0700 | [diff] [blame] | 193 |         } | 
 | 194 |  | 
 | 195 |         if (r == 0) process_cgroup_empty_ = true; | 
 | 196 |     } | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 197 | } | 
 | 198 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 199 | void Service::SetProcessAttributesAndCaps() { | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 200 |     // Keep capabilites on uid change. | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 201 |     if (capabilities_ && proc_attr_.uid) { | 
| Luis Hector Chavez | f596551 | 2017-06-30 14:04:20 -0700 | [diff] [blame] | 202 |         // If Android is running in a container, some securebits might already | 
 | 203 |         // be locked, so don't change those. | 
| Ben Fennema | a724360 | 2017-07-25 14:37:21 -0700 | [diff] [blame] | 204 |         unsigned long securebits = prctl(PR_GET_SECUREBITS); | 
 | 205 |         if (securebits == -1UL) { | 
| Luis Hector Chavez | f596551 | 2017-06-30 14:04:20 -0700 | [diff] [blame] | 206 |             PLOG(FATAL) << "prctl(PR_GET_SECUREBITS) failed for " << name_; | 
 | 207 |         } | 
 | 208 |         securebits |= SECBIT_KEEP_CAPS | SECBIT_KEEP_CAPS_LOCKED; | 
 | 209 |         if (prctl(PR_SET_SECUREBITS, securebits) != 0) { | 
 | 210 |             PLOG(FATAL) << "prctl(PR_SET_SECUREBITS) failed for " << name_; | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 211 |         } | 
 | 212 |     } | 
 | 213 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 214 |     if (auto result = SetProcessAttributes(proc_attr_); !result) { | 
 | 215 |         LOG(FATAL) << "cannot set attribute for " << name_ << ": " << result.error(); | 
 | 216 |     } | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 217 |  | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 218 |     if (!seclabel_.empty()) { | 
 | 219 |         if (setexeccon(seclabel_.c_str()) < 0) { | 
| Elliott Hughes | e18e7e5 | 2016-07-25 18:18:16 -0700 | [diff] [blame] | 220 |             PLOG(FATAL) << "cannot setexeccon('" << seclabel_ << "') for " << name_; | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 221 |         } | 
 | 222 |     } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 223 |  | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 224 |     if (capabilities_) { | 
 | 225 |         if (!SetCapsForExec(*capabilities_)) { | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 226 |             LOG(FATAL) << "cannot set capabilities for " << name_; | 
 | 227 |         } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 228 |     } else if (proc_attr_.uid) { | 
| Luis Hector Chavez | 94fb5b0 | 2017-11-16 15:52:00 -0800 | [diff] [blame] | 229 |         // Inheritable caps can be non-zero when running in a container. | 
 | 230 |         if (!DropInheritableCaps()) { | 
 | 231 |             LOG(FATAL) << "cannot drop inheritable caps for " << name_; | 
 | 232 |         } | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 233 |     } | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 234 | } | 
 | 235 |  | 
| Paul Crowley | c73b215 | 2018-04-13 17:38:57 +0000 | [diff] [blame] | 236 | void Service::Reap(const siginfo_t& siginfo) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 237 |     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 238 |         KillProcessGroup(SIGKILL); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 239 |     } | 
 | 240 |  | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 241 |     // Remove any descriptor resources we may have created. | 
 | 242 |     std::for_each(descriptors_.begin(), descriptors_.end(), | 
 | 243 |                   std::bind(&DescriptorInfo::Clean, std::placeholders::_1)); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 244 |  | 
| Paul Crowley | c73b215 | 2018-04-13 17:38:57 +0000 | [diff] [blame] | 245 |     for (const auto& f : reap_callbacks_) { | 
 | 246 |         f(siginfo); | 
 | 247 |     } | 
 | 248 |  | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 249 |     if (flags_ & SVC_EXEC) UnSetExec(); | 
 | 250 |  | 
 | 251 |     if (flags_ & SVC_TEMPORARY) return; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 252 |  | 
 | 253 |     pid_ = 0; | 
 | 254 |     flags_ &= (~SVC_RUNNING); | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 255 |     start_order_ = 0; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 256 |  | 
 | 257 |     // Oneshot processes go into the disabled state on exit, | 
 | 258 |     // except when manually restarted. | 
| Martijn Coenen | 70788f9 | 2019-04-23 16:26:01 +0200 | [diff] [blame] | 259 |     if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART) && !(flags_ & SVC_RESET)) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 260 |         flags_ |= SVC_DISABLED; | 
 | 261 |     } | 
 | 262 |  | 
 | 263 |     // Disabled and reset processes do not get restarted automatically. | 
 | 264 |     if (flags_ & (SVC_DISABLED | SVC_RESET))  { | 
 | 265 |         NotifyStateChange("stopped"); | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 266 |         return; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 267 |     } | 
 | 268 |  | 
| Jiyong Park | d7f7c20 | 2019-05-10 21:12:15 +0900 | [diff] [blame] | 269 | #if defined(__ANDROID__) | 
 | 270 |     static bool is_apex_updatable = android::sysprop::ApexProperties::updatable().value_or(false); | 
 | 271 | #else | 
 | 272 |     static bool is_apex_updatable = false; | 
 | 273 | #endif | 
 | 274 |     const bool is_process_updatable = !pre_apexd_ && is_apex_updatable; | 
 | 275 |  | 
| Zimuzo | 88de80f | 2019-04-27 21:10:35 +0100 | [diff] [blame] | 276 |     // If we crash > 4 times in 4 minutes or before boot_completed, | 
 | 277 |     // reboot into bootloader or set crashing property | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 278 |     boot_clock::time_point now = boot_clock::now(); | 
| Jiyong Park | d7f7c20 | 2019-05-10 21:12:15 +0900 | [diff] [blame] | 279 |     if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART)) { | 
| Zimuzo | 88de80f | 2019-04-27 21:10:35 +0100 | [diff] [blame] | 280 |         bool boot_completed = android::base::GetBoolProperty("sys.boot_completed", false); | 
 | 281 |         if (now < time_crashed_ + 4min || !boot_completed) { | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 282 |             if (++crash_count_ > 4) { | 
| Zimuzo | c55a8c6 | 2019-01-07 10:19:02 +0000 | [diff] [blame] | 283 |                 if (flags_ & SVC_CRITICAL) { | 
 | 284 |                     // Aborts into bootloader | 
| Zimuzo | 88de80f | 2019-04-27 21:10:35 +0100 | [diff] [blame] | 285 |                     LOG(FATAL) << "critical process '" << name_ << "' exited 4 times " | 
 | 286 |                                << (boot_completed ? "in 4 minutes" : "before boot completed"); | 
| Zimuzo | c55a8c6 | 2019-01-07 10:19:02 +0000 | [diff] [blame] | 287 |                 } else { | 
| Zimuzo | 88de80f | 2019-04-27 21:10:35 +0100 | [diff] [blame] | 288 |                     LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times " | 
 | 289 |                                << (boot_completed ? "in 4 minutes" : "before boot completed"); | 
| Zimuzo | c55a8c6 | 2019-01-07 10:19:02 +0000 | [diff] [blame] | 290 |                     // Notifies update_verifier and apexd | 
 | 291 |                     property_set("ro.init.updatable_crashing", "1"); | 
 | 292 |                 } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 293 |             } | 
 | 294 |         } else { | 
 | 295 |             time_crashed_ = now; | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 296 |             crash_count_ = 1; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 297 |         } | 
 | 298 |     } | 
 | 299 |  | 
 | 300 |     flags_ &= (~SVC_RESTART); | 
 | 301 |     flags_ |= SVC_RESTARTING; | 
 | 302 |  | 
 | 303 |     // Execute all onrestart commands for this service. | 
 | 304 |     onrestart_.ExecuteAllCommands(); | 
 | 305 |  | 
 | 306 |     NotifyStateChange("restarting"); | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 307 |     return; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 308 | } | 
 | 309 |  | 
 | 310 | void Service::DumpState() const { | 
| Elliott Hughes | f86b5a6 | 2016-06-24 15:12:21 -0700 | [diff] [blame] | 311 |     LOG(INFO) << "service " << name_; | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 312 |     LOG(INFO) << "  class '" << Join(classnames_, " ") << "'"; | 
 | 313 |     LOG(INFO) << "  exec " << Join(args_, " "); | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 314 |     std::for_each(descriptors_.begin(), descriptors_.end(), | 
 | 315 |                   [] (const auto& info) { LOG(INFO) << *info; }); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 316 | } | 
 | 317 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 318 | Result<void> Service::ParseCapabilities(std::vector<std::string>&& args) { | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 319 |     capabilities_ = 0; | 
 | 320 |  | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 321 |     if (!CapAmbientSupported()) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 322 |         return Error() | 
 | 323 |                << "capabilities requested but the kernel does not support ambient capabilities"; | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 324 |     } | 
 | 325 |  | 
 | 326 |     unsigned int last_valid_cap = GetLastValidCap(); | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 327 |     if (last_valid_cap >= capabilities_->size()) { | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 328 |         LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP"; | 
 | 329 |     } | 
 | 330 |  | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 331 |     for (size_t i = 1; i < args.size(); i++) { | 
 | 332 |         const std::string& arg = args[i]; | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 333 |         int res = LookupCap(arg); | 
 | 334 |         if (res < 0) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 335 |             return Error() << StringPrintf("invalid capability '%s'", arg.c_str()); | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 336 |         } | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 337 |         unsigned int cap = static_cast<unsigned int>(res);  // |res| is >= 0. | 
 | 338 |         if (cap > last_valid_cap) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 339 |             return Error() << StringPrintf("capability '%s' not supported by the kernel", | 
 | 340 |                                            arg.c_str()); | 
| Jorge Lucangeli Obes | f3f824e | 2016-12-15 12:13:38 -0500 | [diff] [blame] | 341 |         } | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 342 |         (*capabilities_)[cap] = true; | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 343 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 344 |     return {}; | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 345 | } | 
 | 346 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 347 | Result<void> Service::ParseClass(std::vector<std::string>&& args) { | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 348 |     classnames_ = std::set<std::string>(args.begin() + 1, args.end()); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 349 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 350 | } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 351 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 352 | Result<void> Service::ParseConsole(std::vector<std::string>&& args) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 353 |     flags_ |= SVC_CONSOLE; | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 354 |     proc_attr_.console = args.size() > 1 ? "/dev/" + args[1] : ""; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 355 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 356 | } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 357 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 358 | Result<void> Service::ParseCritical(std::vector<std::string>&& args) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 359 |     flags_ |= SVC_CRITICAL; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 360 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 361 | } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 362 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 363 | Result<void> Service::ParseDisabled(std::vector<std::string>&& args) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 364 |     flags_ |= SVC_DISABLED; | 
 | 365 |     flags_ |= SVC_RC_DISABLED; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 366 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 367 | } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 368 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 369 | Result<void> Service::ParseEnterNamespace(std::vector<std::string>&& args) { | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 370 |     if (args[1] != "net") { | 
 | 371 |         return Error() << "Init only supports entering network namespaces"; | 
 | 372 |     } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 373 |     if (!namespaces_.namespaces_to_enter.empty()) { | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 374 |         return Error() << "Only one network namespace may be entered"; | 
 | 375 |     } | 
 | 376 |     // Network namespaces require that /sys is remounted, otherwise the old adapters will still be | 
 | 377 |     // present. Therefore, they also require mount namespaces. | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 378 |     namespaces_.flags |= CLONE_NEWNS; | 
 | 379 |     namespaces_.namespaces_to_enter.emplace_back(CLONE_NEWNET, std::move(args[2])); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 380 |     return {}; | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 381 | } | 
 | 382 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 383 | Result<void> Service::ParseGroup(std::vector<std::string>&& args) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 384 |     auto gid = DecodeUid(args[1]); | 
 | 385 |     if (!gid) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 386 |         return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 387 |     } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 388 |     proc_attr_.gid = *gid; | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 389 |  | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 390 |     for (std::size_t n = 2; n < args.size(); n++) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 391 |         gid = DecodeUid(args[n]); | 
 | 392 |         if (!gid) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 393 |             return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 394 |         } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 395 |         proc_attr_.supp_gids.emplace_back(*gid); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 396 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 397 |     return {}; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 398 | } | 
 | 399 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 400 | Result<void> Service::ParsePriority(std::vector<std::string>&& args) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 401 |     proc_attr_.priority = 0; | 
 | 402 |     if (!ParseInt(args[1], &proc_attr_.priority, | 
 | 403 |                   static_cast<int>(ANDROID_PRIORITY_HIGHEST),  // highest is negative | 
| Keun-young Park | dd34ca4 | 2016-11-11 18:06:31 -0800 | [diff] [blame] | 404 |                   static_cast<int>(ANDROID_PRIORITY_LOWEST))) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 405 |         return Error() << StringPrintf("process priority value must be range %d - %d", | 
 | 406 |                                        ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST); | 
| Vitalii Tomkiv | 081705c | 2016-05-18 17:36:30 -0700 | [diff] [blame] | 407 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 408 |     return {}; | 
| Vitalii Tomkiv | 081705c | 2016-05-18 17:36:30 -0700 | [diff] [blame] | 409 | } | 
 | 410 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 411 | Result<void> Service::ParseInterface(std::vector<std::string>&& args) { | 
| Steven Moreland | e055d73 | 2017-10-05 18:50:22 -0700 | [diff] [blame] | 412 |     const std::string& interface_name = args[1]; | 
 | 413 |     const std::string& instance_name = args[2]; | 
 | 414 |  | 
| Steven Moreland | 422367b | 2018-03-06 14:57:46 -0800 | [diff] [blame] | 415 |     FQName fq_name; | 
 | 416 |     if (!FQName::parse(interface_name, &fq_name)) { | 
| Steven Moreland | e055d73 | 2017-10-05 18:50:22 -0700 | [diff] [blame] | 417 |         return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'"; | 
 | 418 |     } | 
 | 419 |  | 
 | 420 |     if (!fq_name.isFullyQualified()) { | 
 | 421 |         return Error() << "Interface name not fully-qualified '" << interface_name << "'"; | 
 | 422 |     } | 
 | 423 |  | 
 | 424 |     if (fq_name.isValidValueName()) { | 
 | 425 |         return Error() << "Interface name must not be a value name '" << interface_name << "'"; | 
 | 426 |     } | 
 | 427 |  | 
 | 428 |     const std::string fullname = interface_name + "/" + instance_name; | 
 | 429 |  | 
 | 430 |     for (const auto& svc : ServiceList::GetInstance()) { | 
 | 431 |         if (svc->interfaces().count(fullname) > 0) { | 
 | 432 |             return Error() << "Interface '" << fullname << "' redefined in " << name() | 
 | 433 |                            << " but is already defined by " << svc->name(); | 
 | 434 |         } | 
 | 435 |     } | 
 | 436 |  | 
 | 437 |     interfaces_.insert(fullname); | 
 | 438 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 439 |     return {}; | 
| Steven Moreland | e055d73 | 2017-10-05 18:50:22 -0700 | [diff] [blame] | 440 | } | 
 | 441 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 442 | Result<void> Service::ParseIoprio(std::vector<std::string>&& args) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 443 |     if (!ParseInt(args[2], &proc_attr_.ioprio_pri, 0, 7)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 444 |         return Error() << "priority value must be range 0 - 7"; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 445 |     } | 
 | 446 |  | 
 | 447 |     if (args[1] == "rt") { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 448 |         proc_attr_.ioprio_class = IoSchedClass_RT; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 449 |     } else if (args[1] == "be") { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 450 |         proc_attr_.ioprio_class = IoSchedClass_BE; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 451 |     } else if (args[1] == "idle") { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 452 |         proc_attr_.ioprio_class = IoSchedClass_IDLE; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 453 |     } else { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 454 |         return Error() << "ioprio option usage: ioprio <rt|be|idle> <0-7>"; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 455 |     } | 
 | 456 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 457 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 458 | } | 
 | 459 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 460 | Result<void> Service::ParseKeycodes(std::vector<std::string>&& args) { | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 461 |     auto it = args.begin() + 1; | 
 | 462 |     if (args.size() == 2 && StartsWith(args[1], "$")) { | 
 | 463 |         std::string expanded; | 
 | 464 |         if (!expand_props(args[1], &expanded)) { | 
 | 465 |             return Error() << "Could not expand property '" << args[1] << "'"; | 
 | 466 |         } | 
 | 467 |  | 
 | 468 |         // If the property is not set, it defaults to none, in which case there are no keycodes | 
 | 469 |         // for this service. | 
 | 470 |         if (expanded == "none") { | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 471 |             return {}; | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 472 |         } | 
 | 473 |  | 
 | 474 |         args = Split(expanded, ","); | 
 | 475 |         it = args.begin(); | 
 | 476 |     } | 
 | 477 |  | 
 | 478 |     for (; it != args.end(); ++it) { | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 479 |         int code; | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 480 |         if (ParseInt(*it, &code, 0, KEY_MAX)) { | 
| Mark Salyzyn | eca2507 | 2018-05-16 15:10:24 -0700 | [diff] [blame] | 481 |             for (auto& key : keycodes_) { | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 482 |                 if (key == code) return Error() << "duplicate keycode: " << *it; | 
| Mark Salyzyn | eca2507 | 2018-05-16 15:10:24 -0700 | [diff] [blame] | 483 |             } | 
| Mark Salyzyn | 1385725 | 2018-05-18 15:25:15 -0700 | [diff] [blame] | 484 |             keycodes_.insert(std::upper_bound(keycodes_.begin(), keycodes_.end(), code), code); | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 485 |         } else { | 
| Tom Cherry | 7916684 | 2018-10-16 10:58:06 -0700 | [diff] [blame] | 486 |             return Error() << "invalid keycode: " << *it; | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 487 |         } | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 488 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 489 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 490 | } | 
 | 491 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 492 | Result<void> Service::ParseOneshot(std::vector<std::string>&& args) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 493 |     flags_ |= SVC_ONESHOT; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 494 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 495 | } | 
 | 496 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 497 | Result<void> Service::ParseOnrestart(std::vector<std::string>&& args) { | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 498 |     args.erase(args.begin()); | 
| Tom Cherry | 012c573 | 2017-04-18 13:21:54 -0700 | [diff] [blame] | 499 |     int line = onrestart_.NumCommands() + 1; | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 500 |     if (auto result = onrestart_.AddCommand(std::move(args), line); !result) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 501 |         return Error() << "cannot add Onrestart command: " << result.error(); | 
 | 502 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 503 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 504 | } | 
 | 505 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 506 | Result<void> Service::ParseNamespace(std::vector<std::string>&& args) { | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 507 |     for (size_t i = 1; i < args.size(); i++) { | 
 | 508 |         if (args[i] == "pid") { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 509 |             namespaces_.flags |= CLONE_NEWPID; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 510 |             // PID namespaces require mount namespaces. | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 511 |             namespaces_.flags |= CLONE_NEWNS; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 512 |         } else if (args[i] == "mnt") { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 513 |             namespaces_.flags |= CLONE_NEWNS; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 514 |         } else { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 515 |             return Error() << "namespace must be 'pid' or 'mnt'"; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 516 |         } | 
 | 517 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 518 |     return {}; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 519 | } | 
 | 520 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 521 | Result<void> Service::ParseOomScoreAdjust(std::vector<std::string>&& args) { | 
| Elliott Hughes | da46b39 | 2016-10-11 17:09:00 -0700 | [diff] [blame] | 522 |     if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 523 |         return Error() << "oom_score_adjust value must be in range -1000 - +1000"; | 
| Marco Nelissen | 310f670 | 2016-07-22 12:07:06 -0700 | [diff] [blame] | 524 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 525 |     return {}; | 
| Marco Nelissen | 310f670 | 2016-07-22 12:07:06 -0700 | [diff] [blame] | 526 | } | 
 | 527 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 528 | Result<void> Service::ParseOverride(std::vector<std::string>&& args) { | 
| Steven Moreland | 6f5333a | 2017-11-13 15:31:54 -0800 | [diff] [blame] | 529 |     override_ = true; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 530 |     return {}; | 
| Steven Moreland | 6f5333a | 2017-11-13 15:31:54 -0800 | [diff] [blame] | 531 | } | 
 | 532 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 533 | Result<void> Service::ParseMemcgSwappiness(std::vector<std::string>&& args) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 534 |     if (!ParseInt(args[1], &swappiness_, 0)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 535 |         return Error() << "swappiness value must be equal or greater than 0"; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 536 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 537 |     return {}; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 538 | } | 
 | 539 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 540 | Result<void> Service::ParseMemcgLimitInBytes(std::vector<std::string>&& args) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 541 |     if (!ParseInt(args[1], &limit_in_bytes_, 0)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 542 |         return Error() << "limit_in_bytes value must be equal or greater than 0"; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 543 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 544 |     return {}; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 545 | } | 
 | 546 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 547 | Result<void> Service::ParseMemcgLimitPercent(std::vector<std::string>&& args) { | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 548 |     if (!ParseInt(args[1], &limit_percent_, 0)) { | 
 | 549 |         return Error() << "limit_percent value must be equal or greater than 0"; | 
 | 550 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 551 |     return {}; | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 552 | } | 
 | 553 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 554 | Result<void> Service::ParseMemcgLimitProperty(std::vector<std::string>&& args) { | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 555 |     limit_property_ = std::move(args[1]); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 556 |     return {}; | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 557 | } | 
 | 558 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 559 | Result<void> Service::ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 560 |     if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 561 |         return Error() << "soft_limit_in_bytes value must be equal or greater than 0"; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 562 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 563 |     return {}; | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 564 | } | 
 | 565 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 566 | Result<void> Service::ParseProcessRlimit(std::vector<std::string>&& args) { | 
| Tom Cherry | 7ac013d | 2017-08-25 10:39:25 -0700 | [diff] [blame] | 567 |     auto rlimit = ParseRlimit(args); | 
 | 568 |     if (!rlimit) return rlimit.error(); | 
 | 569 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 570 |     proc_attr_.rlimits.emplace_back(*rlimit); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 571 |     return {}; | 
| Tom Cherry | 7ac013d | 2017-08-25 10:39:25 -0700 | [diff] [blame] | 572 | } | 
 | 573 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 574 | Result<void> Service::ParseRestartPeriod(std::vector<std::string>&& args) { | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 575 |     int period; | 
 | 576 |     if (!ParseInt(args[1], &period, 5)) { | 
 | 577 |         return Error() << "restart_period value must be an integer >= 5"; | 
 | 578 |     } | 
 | 579 |     restart_period_ = std::chrono::seconds(period); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 580 |     return {}; | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 581 | } | 
 | 582 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 583 | Result<void> Service::ParseSeclabel(std::vector<std::string>&& args) { | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 584 |     seclabel_ = std::move(args[1]); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 585 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 586 | } | 
 | 587 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 588 | Result<void> Service::ParseSigstop(std::vector<std::string>&& args) { | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 589 |     sigstop_ = true; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 590 |     return {}; | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 591 | } | 
 | 592 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 593 | Result<void> Service::ParseSetenv(std::vector<std::string>&& args) { | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 594 |     environment_vars_.emplace_back(std::move(args[1]), std::move(args[2])); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 595 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 596 | } | 
 | 597 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 598 | Result<void> Service::ParseShutdown(std::vector<std::string>&& args) { | 
| Keun-young Park | cccb34f | 2017-07-05 11:38:44 -0700 | [diff] [blame] | 599 |     if (args[1] == "critical") { | 
 | 600 |         flags_ |= SVC_SHUTDOWN_CRITICAL; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 601 |         return {}; | 
| Keun-young Park | cccb34f | 2017-07-05 11:38:44 -0700 | [diff] [blame] | 602 |     } | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 603 |     return Error() << "Invalid shutdown option"; | 
| Keun-young Park | cccb34f | 2017-07-05 11:38:44 -0700 | [diff] [blame] | 604 | } | 
 | 605 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 606 | Result<void> Service::ParseTimeoutPeriod(std::vector<std::string>&& args) { | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 607 |     int period; | 
 | 608 |     if (!ParseInt(args[1], &period, 1)) { | 
 | 609 |         return Error() << "timeout_period value must be an integer >= 1"; | 
 | 610 |     } | 
 | 611 |     timeout_period_ = std::chrono::seconds(period); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 612 |     return {}; | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 613 | } | 
 | 614 |  | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 615 | template <typename T> | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 616 | Result<void> Service::AddDescriptor(std::vector<std::string>&& args) { | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 617 |     int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1; | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 618 |     Result<uid_t> uid = 0; | 
 | 619 |     Result<gid_t> gid = 0; | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 620 |     std::string context = args.size() > 6 ? args[6] : ""; | 
 | 621 |  | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 622 |     if (args.size() > 4) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 623 |         uid = DecodeUid(args[4]); | 
 | 624 |         if (!uid) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 625 |             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 626 |         } | 
 | 627 |     } | 
 | 628 |  | 
 | 629 |     if (args.size() > 5) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 630 |         gid = DecodeUid(args[5]); | 
 | 631 |         if (!gid) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 632 |             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 633 |         } | 
 | 634 |     } | 
 | 635 |  | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 636 |     auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context); | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 637 |  | 
 | 638 |     auto old = | 
 | 639 |         std::find_if(descriptors_.begin(), descriptors_.end(), | 
 | 640 |                      [&descriptor] (const auto& other) { return descriptor.get() == other.get(); }); | 
 | 641 |  | 
 | 642 |     if (old != descriptors_.end()) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 643 |         return Error() << "duplicate descriptor " << args[1] << " " << args[2]; | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 644 |     } | 
 | 645 |  | 
 | 646 |     descriptors_.emplace_back(std::move(descriptor)); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 647 |     return {}; | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 648 | } | 
 | 649 |  | 
 | 650 | // name type perm [ uid gid context ] | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 651 | Result<void> Service::ParseSocket(std::vector<std::string>&& args) { | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 652 |     if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") && | 
 | 653 |         !StartsWith(args[2], "seqpacket")) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 654 |         return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'"; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 655 |     } | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 656 |     return AddDescriptor<SocketInfo>(std::move(args)); | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 657 | } | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 658 |  | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 659 | // name type perm [ uid gid context ] | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 660 | Result<void> Service::ParseFile(std::vector<std::string>&& args) { | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 661 |     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 662 |         return Error() << "file type must be 'r', 'w' or 'rw'"; | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 663 |     } | 
| Yifan Hong | 567f187 | 2019-03-19 14:38:48 -0700 | [diff] [blame] | 664 |     std::string expanded; | 
 | 665 |     if (!expand_props(args[1], &expanded)) { | 
 | 666 |         return Error() << "Could not expand property in file path '" << args[1] << "'"; | 
 | 667 |     } | 
 | 668 |     args[1] = std::move(expanded); | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 669 |     if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 670 |         return Error() << "file name must not be relative"; | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 671 |     } | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 672 |     return AddDescriptor<FileInfo>(std::move(args)); | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 673 | } | 
 | 674 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 675 | Result<void> Service::ParseUser(std::vector<std::string>&& args) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 676 |     auto uid = DecodeUid(args[1]); | 
 | 677 |     if (!uid) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 678 |         return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 679 |     } | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 680 |     proc_attr_.uid = *uid; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 681 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 682 | } | 
 | 683 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 684 | Result<void> Service::ParseWritepid(std::vector<std::string>&& args) { | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 685 |     args.erase(args.begin()); | 
 | 686 |     writepid_files_ = std::move(args); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 687 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 688 | } | 
 | 689 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 690 | Result<void> Service::ParseUpdatable(std::vector<std::string>&& args) { | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 691 |     updatable_ = true; | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 692 |     return {}; | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 693 | } | 
 | 694 |  | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 695 | class Service::OptionParserMap : public KeywordMap<OptionParser> { | 
| Tom Cherry | ad54d09 | 2017-04-19 16:18:50 -0700 | [diff] [blame] | 696 |   public: | 
 | 697 |     OptionParserMap() {} | 
 | 698 |  | 
 | 699 |   private: | 
 | 700 |     const Map& map() const override; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 701 | }; | 
 | 702 |  | 
| Tom Cherry | ad54d09 | 2017-04-19 16:18:50 -0700 | [diff] [blame] | 703 | const Service::OptionParserMap::Map& Service::OptionParserMap::map() const { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 704 |     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 705 |     // clang-format off | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 706 |     static const Map option_parsers = { | 
| Jorge Lucangeli Obes | 24b2913 | 2016-10-27 10:33:03 -0400 | [diff] [blame] | 707 |         {"capabilities", | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 708 |                         {0,     kMax, &Service::ParseCapabilities}}, | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 709 |         {"class",       {1,     kMax, &Service::ParseClass}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 710 |         {"console",     {0,     1,    &Service::ParseConsole}}, | 
 | 711 |         {"critical",    {0,     0,    &Service::ParseCritical}}, | 
 | 712 |         {"disabled",    {0,     0,    &Service::ParseDisabled}}, | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 713 |         {"enter_namespace", | 
 | 714 |                         {2,     2,    &Service::ParseEnterNamespace}}, | 
| Tom Cherry | e2f341e | 2018-03-08 13:51:10 -0800 | [diff] [blame] | 715 |         {"file",        {2,     2,    &Service::ParseFile}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 716 |         {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}}, | 
| Steven Moreland | e055d73 | 2017-10-05 18:50:22 -0700 | [diff] [blame] | 717 |         {"interface",   {2,     2,    &Service::ParseInterface}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 718 |         {"ioprio",      {2,     2,    &Service::ParseIoprio}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 719 |         {"keycodes",    {1,     kMax, &Service::ParseKeycodes}}, | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 720 |         {"memcg.limit_in_bytes", | 
 | 721 |                         {1,     1,    &Service::ParseMemcgLimitInBytes}}, | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 722 |         {"memcg.limit_percent", | 
 | 723 |                         {1,     1,    &Service::ParseMemcgLimitPercent}}, | 
 | 724 |         {"memcg.limit_property", | 
 | 725 |                         {1,     1,    &Service::ParseMemcgLimitProperty}}, | 
| Tom Cherry | e2f341e | 2018-03-08 13:51:10 -0800 | [diff] [blame] | 726 |         {"memcg.soft_limit_in_bytes", | 
 | 727 |                         {1,     1,    &Service::ParseMemcgSoftLimitInBytes}}, | 
 | 728 |         {"memcg.swappiness", | 
 | 729 |                         {1,     1,    &Service::ParseMemcgSwappiness}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 730 |         {"namespace",   {1,     2,    &Service::ParseNamespace}}, | 
| Tom Cherry | e2f341e | 2018-03-08 13:51:10 -0800 | [diff] [blame] | 731 |         {"oneshot",     {0,     0,    &Service::ParseOneshot}}, | 
 | 732 |         {"onrestart",   {1,     kMax, &Service::ParseOnrestart}}, | 
 | 733 |         {"oom_score_adjust", | 
 | 734 |                         {1,     1,    &Service::ParseOomScoreAdjust}}, | 
 | 735 |         {"override",    {0,     0,    &Service::ParseOverride}}, | 
 | 736 |         {"priority",    {1,     1,    &Service::ParsePriority}}, | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 737 |         {"restart_period", | 
 | 738 |                         {1,     1,    &Service::ParseRestartPeriod}}, | 
| Tom Cherry | 7ac013d | 2017-08-25 10:39:25 -0700 | [diff] [blame] | 739 |         {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 740 |         {"seclabel",    {1,     1,    &Service::ParseSeclabel}}, | 
 | 741 |         {"setenv",      {2,     2,    &Service::ParseSetenv}}, | 
| Keun-young Park | cccb34f | 2017-07-05 11:38:44 -0700 | [diff] [blame] | 742 |         {"shutdown",    {1,     1,    &Service::ParseShutdown}}, | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 743 |         {"sigstop",     {0,     0,    &Service::ParseSigstop}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 744 |         {"socket",      {3,     6,    &Service::ParseSocket}}, | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 745 |         {"timeout_period", | 
 | 746 |                         {1,     1,    &Service::ParseTimeoutPeriod}}, | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 747 |         {"updatable",   {0,     0,    &Service::ParseUpdatable}}, | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 748 |         {"user",        {1,     1,    &Service::ParseUser}}, | 
 | 749 |         {"writepid",    {1,     kMax, &Service::ParseWritepid}}, | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 750 |     }; | 
| Wei Wang | 641ff0a | 2017-03-27 10:59:11 -0700 | [diff] [blame] | 751 |     // clang-format on | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 752 |     return option_parsers; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 753 | } | 
 | 754 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 755 | Result<void> Service::ParseLine(std::vector<std::string>&& args) { | 
| Jorge Lucangeli Obes | 177b27d | 2016-06-29 14:32:49 -0400 | [diff] [blame] | 756 |     static const OptionParserMap parser_map; | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 757 |     auto parser = parser_map.FindFunction(args); | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 758 |  | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 759 |     if (!parser) return parser.error(); | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 760 |  | 
| Tom Cherry | 018a438 | 2018-10-17 11:11:23 -0700 | [diff] [blame] | 761 |     return std::invoke(*parser, this, std::move(args)); | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 762 | } | 
 | 763 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 764 | Result<void> Service::ExecStart() { | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 765 |     if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) { | 
 | 766 |         // Don't delay the service for ExecStart() as the semantic is that | 
 | 767 |         // the caller might depend on the side effect of the execution. | 
 | 768 |         return Error() << "Cannot start an updatable service '" << name_ | 
 | 769 |                        << "' before configs from APEXes are all loaded"; | 
 | 770 |     } | 
 | 771 |  | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 772 |     flags_ |= SVC_ONESHOT; | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 773 |  | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 774 |     if (auto result = Start(); !result) { | 
 | 775 |         return result; | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 776 |     } | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 777 |  | 
 | 778 |     flags_ |= SVC_EXEC; | 
 | 779 |     is_exec_service_running_ = true; | 
 | 780 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 781 |     LOG(INFO) << "SVC_EXEC service '" << name_ << "' pid " << pid_ << " (uid " << proc_attr_.uid | 
 | 782 |               << " gid " << proc_attr_.gid << "+" << proc_attr_.supp_gids.size() << " context " | 
| Wei Wang | 2c4ee75 | 2018-06-20 14:54:52 -0700 | [diff] [blame] | 783 |               << (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting..."; | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 784 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 785 |     return {}; | 
| Tom Cherry | b27004a | 2017-03-27 16:27:30 -0700 | [diff] [blame] | 786 | } | 
 | 787 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 788 | Result<void> Service::Start() { | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 789 |     if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) { | 
 | 790 |         ServiceList::GetInstance().DelayService(*this); | 
 | 791 |         return Error() << "Cannot start an updatable service '" << name_ | 
 | 792 |                        << "' before configs from APEXes are all loaded. " | 
 | 793 |                        << "Queued for execution."; | 
 | 794 |     } | 
 | 795 |  | 
| Tao Wu | 990d43c | 2017-10-26 10:43:10 -0700 | [diff] [blame] | 796 |     bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET)); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 797 |     // Starting a service removes it from the disabled or reset state and | 
 | 798 |     // immediately takes it out of the restarting state if it was in there. | 
 | 799 |     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 800 |  | 
 | 801 |     // Running processes require no additional work --- if they're in the | 
 | 802 |     // process of exiting, we've ensured that they will immediately restart | 
| Tao Wu | 990d43c | 2017-10-26 10:43:10 -0700 | [diff] [blame] | 803 |     // on exit, unless they are ONESHOT. For ONESHOT service, if it's in | 
 | 804 |     // stopping status, we just set SVC_RESTART flag so it will get restarted | 
 | 805 |     // in Reap(). | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 806 |     if (flags_ & SVC_RUNNING) { | 
| Tao Wu | 990d43c | 2017-10-26 10:43:10 -0700 | [diff] [blame] | 807 |         if ((flags_ & SVC_ONESHOT) && disabled) { | 
 | 808 |             flags_ |= SVC_RESTART; | 
 | 809 |         } | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 810 |         // It is not an error to try to start a service that is already running. | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 811 |         return {}; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 812 |     } | 
 | 813 |  | 
 | 814 |     bool needs_console = (flags_ & SVC_CONSOLE); | 
| Viorel Suman | 70daa67 | 2016-03-21 10:08:07 +0200 | [diff] [blame] | 815 |     if (needs_console) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 816 |         if (proc_attr_.console.empty()) { | 
 | 817 |             proc_attr_.console = default_console; | 
| Viorel Suman | 70daa67 | 2016-03-21 10:08:07 +0200 | [diff] [blame] | 818 |         } | 
 | 819 |  | 
| Adrian Salido | 24ef860 | 2016-12-20 15:52:15 -0800 | [diff] [blame] | 820 |         // Make sure that open call succeeds to ensure a console driver is | 
 | 821 |         // properly registered for the device node | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 822 |         int console_fd = open(proc_attr_.console.c_str(), O_RDWR | O_CLOEXEC); | 
| Adrian Salido | 24ef860 | 2016-12-20 15:52:15 -0800 | [diff] [blame] | 823 |         if (console_fd < 0) { | 
| Viorel Suman | 70daa67 | 2016-03-21 10:08:07 +0200 | [diff] [blame] | 824 |             flags_ |= SVC_DISABLED; | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 825 |             return ErrnoError() << "Couldn't open console '" << proc_attr_.console << "'"; | 
| Viorel Suman | 70daa67 | 2016-03-21 10:08:07 +0200 | [diff] [blame] | 826 |         } | 
| Adrian Salido | 24ef860 | 2016-12-20 15:52:15 -0800 | [diff] [blame] | 827 |         close(console_fd); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 828 |     } | 
 | 829 |  | 
 | 830 |     struct stat sb; | 
 | 831 |     if (stat(args_[0].c_str(), &sb) == -1) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 832 |         flags_ |= SVC_DISABLED; | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 833 |         return ErrnoError() << "Cannot find '" << args_[0] << "'"; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 834 |     } | 
 | 835 |  | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 836 |     std::string scon; | 
 | 837 |     if (!seclabel_.empty()) { | 
 | 838 |         scon = seclabel_; | 
 | 839 |     } else { | 
| Tom Cherry | aead51b | 2018-04-20 16:18:12 -0700 | [diff] [blame] | 840 |         auto result = ComputeContextFromExecutable(args_[0]); | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 841 |         if (!result) { | 
 | 842 |             return result.error(); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 843 |         } | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 844 |         scon = *result; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 845 |     } | 
 | 846 |  | 
| Jiyong Park | 6866041 | 2019-01-16 23:00:59 +0900 | [diff] [blame] | 847 |     if (!IsRuntimeApexReady() && !pre_apexd_) { | 
 | 848 |         // If this service is started before the runtime APEX gets available, | 
 | 849 |         // mark it as pre-apexd one. Note that this marking is permanent. So | 
 | 850 |         // for example, if the service is re-launched (e.g., due to crash), | 
 | 851 |         // it is still recognized as pre-apexd... for consistency. | 
 | 852 |         pre_apexd_ = true; | 
 | 853 |     } | 
 | 854 |  | 
| Martijn Coenen | 70788f9 | 2019-04-23 16:26:01 +0200 | [diff] [blame] | 855 |     post_data_ = ServiceList::GetInstance().IsPostData(); | 
 | 856 |  | 
| Wei Wang | a285dac | 2016-10-04 14:05:39 -0700 | [diff] [blame] | 857 |     LOG(INFO) << "starting service '" << name_ << "'..."; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 858 |  | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 859 |     pid_t pid = -1; | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 860 |     if (namespaces_.flags) { | 
 | 861 |         pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr); | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 862 |     } else { | 
 | 863 |         pid = fork(); | 
 | 864 |     } | 
 | 865 |  | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 866 |     if (pid == 0) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 867 |         umask(077); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 868 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 869 |         if (auto result = EnterNamespaces(namespaces_, name_, pre_apexd_); !result) { | 
 | 870 |             LOG(FATAL) << "Service '" << name_ | 
 | 871 |                        << "' failed to set up namespaces: " << result.error(); | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 872 |         } | 
 | 873 |  | 
| Tom Cherry | 6de21f1 | 2017-08-22 15:41:03 -0700 | [diff] [blame] | 874 |         for (const auto& [key, value] : environment_vars_) { | 
 | 875 |             setenv(key.c_str(), value.c_str(), 1); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 876 |         } | 
 | 877 |  | 
| Mark Salyzyn | 62767fe | 2016-10-27 07:45:34 -0700 | [diff] [blame] | 878 |         std::for_each(descriptors_.begin(), descriptors_.end(), | 
 | 879 |                       std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon)); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 880 |  | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 881 |         if (auto result = WritePidToFiles(&writepid_files_); !result) { | 
 | 882 |             LOG(ERROR) << "failed to write pid to files: " << result.error(); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 883 |         } | 
 | 884 |  | 
| Jorge Lucangeli Obes | 344d01f | 2016-07-08 13:32:26 -0400 | [diff] [blame] | 885 |         // As requested, set our gid, supplemental gids, uid, context, and | 
 | 886 |         // priority. Aborts on failure. | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 887 |         SetProcessAttributesAndCaps(); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 888 |  | 
| Tom Cherry | 8f38048 | 2018-04-17 14:48:44 -0700 | [diff] [blame] | 889 |         if (!ExpandArgsAndExecv(args_, sigstop_)) { | 
| Tom Cherry | 5e405ca | 2017-09-11 16:08:54 -0700 | [diff] [blame] | 890 |             PLOG(ERROR) << "cannot execve('" << args_[0] << "')"; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 891 |         } | 
 | 892 |  | 
 | 893 |         _exit(127); | 
 | 894 |     } | 
 | 895 |  | 
 | 896 |     if (pid < 0) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 897 |         pid_ = 0; | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 898 |         return ErrnoError() << "Failed to fork"; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 899 |     } | 
 | 900 |  | 
| Marco Nelissen | 310f670 | 2016-07-22 12:07:06 -0700 | [diff] [blame] | 901 |     if (oom_score_adjust_ != -1000) { | 
| Tom Cherry | 1c3a53f | 2017-06-22 16:50:31 -0700 | [diff] [blame] | 902 |         std::string oom_str = std::to_string(oom_score_adjust_); | 
| Marco Nelissen | 310f670 | 2016-07-22 12:07:06 -0700 | [diff] [blame] | 903 |         std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid); | 
 | 904 |         if (!WriteStringToFile(oom_str, oom_file)) { | 
| Elliott Hughes | 076305e | 2019-03-08 12:34:53 -0800 | [diff] [blame] | 905 |             PLOG(ERROR) << "couldn't write oom_score_adj"; | 
| Marco Nelissen | 310f670 | 2016-07-22 12:07:06 -0700 | [diff] [blame] | 906 |         } | 
 | 907 |     } | 
 | 908 |  | 
| Elliott Hughes | 9605a94 | 2016-11-10 17:43:47 -0800 | [diff] [blame] | 909 |     time_started_ = boot_clock::now(); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 910 |     pid_ = pid; | 
 | 911 |     flags_ |= SVC_RUNNING; | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 912 |     start_order_ = next_start_order_++; | 
| Tom Cherry | 33838b1 | 2017-05-04 11:32:36 -0700 | [diff] [blame] | 913 |     process_cgroup_empty_ = false; | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 914 |  | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 915 |     bool use_memcg = swappiness_ != -1 || soft_limit_in_bytes_ != -1 || limit_in_bytes_ != -1 || | 
 | 916 |                       limit_percent_ != -1 || !limit_property_.empty(); | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 917 |     errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg); | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 918 |     if (errno != 0) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 919 |         PLOG(ERROR) << "createProcessGroup(" << proc_attr_.uid << ", " << pid_ | 
 | 920 |                     << ") failed for service '" << name_ << "'"; | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 921 |     } else if (use_memcg) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 922 |         if (swappiness_ != -1) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 923 |             if (!setProcessGroupSwappiness(proc_attr_.uid, pid_, swappiness_)) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 924 |                 PLOG(ERROR) << "setProcessGroupSwappiness failed"; | 
 | 925 |             } | 
 | 926 |         } | 
 | 927 |  | 
 | 928 |         if (soft_limit_in_bytes_ != -1) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 929 |             if (!setProcessGroupSoftLimit(proc_attr_.uid, pid_, soft_limit_in_bytes_)) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 930 |                 PLOG(ERROR) << "setProcessGroupSoftLimit failed"; | 
 | 931 |             } | 
 | 932 |         } | 
 | 933 |  | 
| Peter Collingbourne | d7157c2 | 2018-10-30 15:49:33 -0700 | [diff] [blame] | 934 |         size_t computed_limit_in_bytes = limit_in_bytes_; | 
 | 935 |         if (limit_percent_ != -1) { | 
 | 936 |             long page_size = sysconf(_SC_PAGESIZE); | 
 | 937 |             long num_pages = sysconf(_SC_PHYS_PAGES); | 
 | 938 |             if (page_size > 0 && num_pages > 0) { | 
 | 939 |                 size_t max_mem = SIZE_MAX; | 
 | 940 |                 if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) { | 
 | 941 |                     max_mem = size_t(num_pages) * size_t(page_size); | 
 | 942 |                 } | 
 | 943 |                 computed_limit_in_bytes = | 
 | 944 |                         std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_); | 
 | 945 |             } | 
 | 946 |         } | 
 | 947 |  | 
 | 948 |         if (!limit_property_.empty()) { | 
 | 949 |             // This ends up overwriting computed_limit_in_bytes but only if the | 
 | 950 |             // property is defined. | 
 | 951 |             computed_limit_in_bytes = android::base::GetUintProperty( | 
 | 952 |                     limit_property_, computed_limit_in_bytes, SIZE_MAX); | 
 | 953 |         } | 
 | 954 |  | 
 | 955 |         if (computed_limit_in_bytes != size_t(-1)) { | 
| Vic Yang | e01ca4d | 2019-05-29 15:58:32 -0700 | [diff] [blame] | 956 |             if (!setProcessGroupLimit(proc_attr_.uid, pid_, computed_limit_in_bytes)) { | 
| Robert Benea | d485226 | 2017-07-16 19:38:11 -0700 | [diff] [blame] | 957 |                 PLOG(ERROR) << "setProcessGroupLimit failed"; | 
 | 958 |             } | 
 | 959 |         } | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 960 |     } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 961 |  | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 962 |     NotifyStateChange("running"); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 963 |     return {}; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 964 | } | 
 | 965 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 966 | Result<void> Service::StartIfNotDisabled() { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 967 |     if (!(flags_ & SVC_DISABLED)) { | 
 | 968 |         return Start(); | 
 | 969 |     } else { | 
 | 970 |         flags_ |= SVC_DISABLED_START; | 
 | 971 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 972 |     return {}; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 973 | } | 
 | 974 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 975 | Result<void> Service::Enable() { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 976 |     flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED); | 
 | 977 |     if (flags_ & SVC_DISABLED_START) { | 
 | 978 |         return Start(); | 
 | 979 |     } | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 980 |     return {}; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 981 | } | 
 | 982 |  | 
 | 983 | void Service::Reset() { | 
 | 984 |     StopOrReset(SVC_RESET); | 
 | 985 | } | 
 | 986 |  | 
| Martijn Coenen | 70788f9 | 2019-04-23 16:26:01 +0200 | [diff] [blame] | 987 | void Service::ResetIfPostData() { | 
 | 988 |     if (post_data_) { | 
| Martijn Coenen | acc45aa | 2019-05-15 22:04:13 +0200 | [diff] [blame] | 989 |         if (flags_ & SVC_RUNNING) { | 
 | 990 |             running_at_post_data_reset_ = true; | 
 | 991 |         } | 
| Martijn Coenen | 70788f9 | 2019-04-23 16:26:01 +0200 | [diff] [blame] | 992 |         StopOrReset(SVC_RESET); | 
 | 993 |     } | 
 | 994 | } | 
 | 995 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 996 | Result<void> Service::StartIfPostData() { | 
| Martijn Coenen | acc45aa | 2019-05-15 22:04:13 +0200 | [diff] [blame] | 997 |     // Start the service, but only if it was started after /data was mounted, | 
 | 998 |     // and it was still running when we reset the post-data services. | 
 | 999 |     if (running_at_post_data_reset_) { | 
 | 1000 |         return Start(); | 
 | 1001 |     } | 
 | 1002 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1003 |     return {}; | 
| Martijn Coenen | acc45aa | 2019-05-15 22:04:13 +0200 | [diff] [blame] | 1004 | } | 
 | 1005 |  | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1006 | void Service::Stop() { | 
 | 1007 |     StopOrReset(SVC_DISABLED); | 
 | 1008 | } | 
 | 1009 |  | 
| Bertrand SIMONNET | b7e03e8 | 2015-12-18 11:39:59 -0800 | [diff] [blame] | 1010 | void Service::Terminate() { | 
 | 1011 |     flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START); | 
 | 1012 |     flags_ |= SVC_DISABLED; | 
 | 1013 |     if (pid_) { | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1014 |         KillProcessGroup(SIGTERM); | 
| Bertrand SIMONNET | b7e03e8 | 2015-12-18 11:39:59 -0800 | [diff] [blame] | 1015 |         NotifyStateChange("stopping"); | 
 | 1016 |     } | 
 | 1017 | } | 
 | 1018 |  | 
| Tom Cherry | 73f535e | 2018-09-27 16:10:46 -0700 | [diff] [blame] | 1019 | void Service::Timeout() { | 
 | 1020 |     // All process state flags will be taken care of in Reap(), we really just want to kill the | 
 | 1021 |     // process here when it times out.  Oneshot processes will transition to be disabled, and | 
 | 1022 |     // all other processes will transition to be restarting. | 
 | 1023 |     LOG(INFO) << "Service '" << name_ << "' expired its timeout of " << timeout_period_->count() | 
 | 1024 |               << " seconds and will now be killed"; | 
 | 1025 |     if (pid_) { | 
 | 1026 |         KillProcessGroup(SIGKILL); | 
 | 1027 |         NotifyStateChange("stopping"); | 
 | 1028 |     } | 
 | 1029 | } | 
 | 1030 |  | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1031 | void Service::Restart() { | 
 | 1032 |     if (flags_ & SVC_RUNNING) { | 
 | 1033 |         /* Stop, wait, then start the service. */ | 
 | 1034 |         StopOrReset(SVC_RESTART); | 
 | 1035 |     } else if (!(flags_ & SVC_RESTARTING)) { | 
 | 1036 |         /* Just start the service since it's not running. */ | 
| Tom Cherry | 76af7e6 | 2017-08-22 16:13:59 -0700 | [diff] [blame] | 1037 |         if (auto result = Start(); !result) { | 
 | 1038 |             LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error(); | 
 | 1039 |         } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1040 |     } /* else: Service is restarting anyways. */ | 
 | 1041 | } | 
 | 1042 |  | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1043 | // The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART. | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1044 | void Service::StopOrReset(int how) { | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1045 |     // The service is still SVC_RUNNING until its process exits, but if it has | 
 | 1046 |     // already exited it shoudn't attempt a restart yet. | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1047 |     flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START); | 
 | 1048 |  | 
 | 1049 |     if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) { | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1050 |         // An illegal flag: default to SVC_DISABLED. | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1051 |         how = SVC_DISABLED; | 
 | 1052 |     } | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1053 |  | 
 | 1054 |     // If the service has not yet started, prevent it from auto-starting with its class. | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1055 |     if (how == SVC_RESET) { | 
 | 1056 |         flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET; | 
 | 1057 |     } else { | 
 | 1058 |         flags_ |= how; | 
 | 1059 |     } | 
| Tao Wu | 84b856d | 2017-10-27 11:29:13 -0700 | [diff] [blame] | 1060 |     // Make sure it's in right status when a restart immediately follow a | 
 | 1061 |     // stop/reset or vice versa. | 
 | 1062 |     if (how == SVC_RESTART) { | 
 | 1063 |         flags_ &= (~(SVC_DISABLED | SVC_RESET)); | 
 | 1064 |     } else { | 
 | 1065 |         flags_ &= (~SVC_RESTART); | 
 | 1066 |     } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1067 |  | 
 | 1068 |     if (pid_) { | 
| Elliott Hughes | ad8e94e | 2016-06-15 14:49:57 -0700 | [diff] [blame] | 1069 |         KillProcessGroup(SIGKILL); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1070 |         NotifyStateChange("stopping"); | 
 | 1071 |     } else { | 
 | 1072 |         NotifyStateChange("stopped"); | 
 | 1073 |     } | 
 | 1074 | } | 
 | 1075 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1076 | ServiceList::ServiceList() {} | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1077 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1078 | ServiceList& ServiceList::GetInstance() { | 
 | 1079 |     static ServiceList instance; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1080 |     return instance; | 
 | 1081 | } | 
 | 1082 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1083 | void ServiceList::AddService(std::unique_ptr<Service> service) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1084 |     services_.emplace_back(std::move(service)); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1085 | } | 
 | 1086 |  | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 1087 | std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<std::string>& args) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1088 |     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... | 
 | 1089 |     // SECLABEL can be a - to denote default | 
 | 1090 |     std::size_t command_arg = 1; | 
 | 1091 |     for (std::size_t i = 1; i < args.size(); ++i) { | 
 | 1092 |         if (args[i] == "--") { | 
 | 1093 |             command_arg = i + 1; | 
 | 1094 |             break; | 
 | 1095 |         } | 
 | 1096 |     } | 
 | 1097 |     if (command_arg > 4 + NR_SVC_SUPP_GIDS) { | 
| Elliott Hughes | f86b5a6 | 2016-06-24 15:12:21 -0700 | [diff] [blame] | 1098 |         LOG(ERROR) << "exec called with too many supplementary group ids"; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1099 |         return nullptr; | 
 | 1100 |     } | 
 | 1101 |  | 
 | 1102 |     if (command_arg >= args.size()) { | 
| Elliott Hughes | f86b5a6 | 2016-06-24 15:12:21 -0700 | [diff] [blame] | 1103 |         LOG(ERROR) << "exec called without command"; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1104 |         return nullptr; | 
 | 1105 |     } | 
 | 1106 |     std::vector<std::string> str_args(args.begin() + command_arg, args.end()); | 
 | 1107 |  | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 1108 |     static size_t exec_count = 0; | 
 | 1109 |     exec_count++; | 
 | 1110 |     std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")"; | 
| Tom Cherry | 86e31a8 | 2017-04-25 17:31:06 -0700 | [diff] [blame] | 1111 |  | 
| Tom Cherry | 3b81f2d | 2017-07-28 14:48:41 -0700 | [diff] [blame] | 1112 |     unsigned flags = SVC_ONESHOT | SVC_TEMPORARY; | 
| Jorge Lucangeli Obes | 1b3fa3d | 2016-04-21 15:35:09 -0700 | [diff] [blame] | 1113 |     unsigned namespace_flags = 0; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1114 |  | 
 | 1115 |     std::string seclabel = ""; | 
 | 1116 |     if (command_arg > 2 && args[1] != "-") { | 
 | 1117 |         seclabel = args[1]; | 
 | 1118 |     } | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1119 |     Result<uid_t> uid = 0; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1120 |     if (command_arg > 3) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1121 |         uid = DecodeUid(args[2]); | 
 | 1122 |         if (!uid) { | 
 | 1123 |             LOG(ERROR) << "Unable to decode UID for '" << args[2] << "': " << uid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 1124 |             return nullptr; | 
 | 1125 |         } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1126 |     } | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1127 |     Result<gid_t> gid = 0; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1128 |     std::vector<gid_t> supp_gids; | 
 | 1129 |     if (command_arg > 4) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1130 |         gid = DecodeUid(args[3]); | 
 | 1131 |         if (!gid) { | 
 | 1132 |             LOG(ERROR) << "Unable to decode GID for '" << args[3] << "': " << gid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 1133 |             return nullptr; | 
 | 1134 |         } | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1135 |         std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */; | 
 | 1136 |         for (size_t i = 0; i < nr_supp_gids; ++i) { | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1137 |             auto supp_gid = DecodeUid(args[4 + i]); | 
 | 1138 |             if (!supp_gid) { | 
 | 1139 |                 LOG(ERROR) << "Unable to decode GID for '" << args[4 + i] | 
 | 1140 |                            << "': " << supp_gid.error(); | 
| Tom Cherry | 517e1f1 | 2017-05-04 17:40:33 -0700 | [diff] [blame] | 1141 |                 return nullptr; | 
 | 1142 |             } | 
| Tom Cherry | 11a3aee | 2017-08-03 12:54:07 -0700 | [diff] [blame] | 1143 |             supp_gids.push_back(*supp_gid); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1144 |         } | 
 | 1145 |     } | 
 | 1146 |  | 
| Tom Cherry | 1cd082d | 2019-02-06 10:45:56 -0800 | [diff] [blame] | 1147 |     return std::make_unique<Service>(name, flags, *uid, *gid, supp_gids, namespace_flags, seclabel, | 
 | 1148 |                                      nullptr, str_args); | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1149 | } | 
 | 1150 |  | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 1151 | // Shutdown services in the opposite order that they were started. | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1152 | const std::vector<Service*> ServiceList::services_in_shutdown_order() const { | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 1153 |     std::vector<Service*> shutdown_services; | 
 | 1154 |     for (const auto& service : services_) { | 
 | 1155 |         if (service->start_order() > 0) shutdown_services.emplace_back(service.get()); | 
 | 1156 |     } | 
 | 1157 |     std::sort(shutdown_services.begin(), shutdown_services.end(), | 
 | 1158 |               [](const auto& a, const auto& b) { return a->start_order() > b->start_order(); }); | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1159 |     return shutdown_services; | 
| Tom Cherry | 5938379 | 2017-07-26 16:09:09 -0700 | [diff] [blame] | 1160 | } | 
 | 1161 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1162 | void ServiceList::RemoveService(const Service& svc) { | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1163 |     auto svc_it = std::find_if(services_.begin(), services_.end(), | 
 | 1164 |                                [&svc] (const std::unique_ptr<Service>& s) { | 
 | 1165 |                                    return svc.name() == s->name(); | 
 | 1166 |                                }); | 
 | 1167 |     if (svc_it == services_.end()) { | 
 | 1168 |         return; | 
 | 1169 |     } | 
 | 1170 |  | 
 | 1171 |     services_.erase(svc_it); | 
 | 1172 | } | 
 | 1173 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1174 | void ServiceList::DumpState() const { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1175 |     for (const auto& s : services_) { | 
 | 1176 |         s->DumpState(); | 
 | 1177 |     } | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1178 | } | 
 | 1179 |  | 
| Martijn Coenen | 70788f9 | 2019-04-23 16:26:01 +0200 | [diff] [blame] | 1180 | void ServiceList::MarkPostData() { | 
 | 1181 |     post_data_ = true; | 
 | 1182 | } | 
 | 1183 |  | 
 | 1184 | bool ServiceList::IsPostData() { | 
 | 1185 |     return post_data_; | 
 | 1186 | } | 
 | 1187 |  | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 1188 | void ServiceList::MarkServicesUpdate() { | 
 | 1189 |     services_update_finished_ = true; | 
 | 1190 |  | 
 | 1191 |     // start the delayed services | 
 | 1192 |     for (const auto& name : delayed_service_names_) { | 
 | 1193 |         Service* service = FindService(name); | 
 | 1194 |         if (service == nullptr) { | 
 | 1195 |             LOG(ERROR) << "delayed service '" << name << "' could not be found."; | 
 | 1196 |             continue; | 
 | 1197 |         } | 
 | 1198 |         if (auto result = service->Start(); !result) { | 
| Jiyong Park | 8fd64c8 | 2019-05-31 03:43:34 +0900 | [diff] [blame] | 1199 |             LOG(ERROR) << result.error().message(); | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 1200 |         } | 
 | 1201 |     } | 
 | 1202 |     delayed_service_names_.clear(); | 
 | 1203 | } | 
 | 1204 |  | 
 | 1205 | void ServiceList::DelayService(const Service& service) { | 
 | 1206 |     if (services_update_finished_) { | 
 | 1207 |         LOG(ERROR) << "Cannot delay the start of service '" << service.name() | 
 | 1208 |                    << "' because all services are already updated. Ignoring."; | 
 | 1209 |         return; | 
 | 1210 |     } | 
 | 1211 |     delayed_service_names_.emplace_back(service.name()); | 
 | 1212 | } | 
 | 1213 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1214 | Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args, | 
 | 1215 |                                          const std::string& filename, int line) { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1216 |     if (args.size() < 3) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 1217 |         return Error() << "services must have a name and a program"; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1218 |     } | 
 | 1219 |  | 
 | 1220 |     const std::string& name = args[1]; | 
 | 1221 |     if (!IsValidName(name)) { | 
| Tom Cherry | 89bcc85 | 2017-08-02 17:01:36 -0700 | [diff] [blame] | 1222 |         return Error() << "invalid service name '" << name << "'"; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1223 |     } | 
 | 1224 |  | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 1225 |     filename_ = filename; | 
 | 1226 |  | 
| Tom Cherry | cb0f9bb | 2017-09-12 15:58:47 -0700 | [diff] [blame] | 1227 |     Subcontext* restart_action_subcontext = nullptr; | 
 | 1228 |     if (subcontexts_) { | 
 | 1229 |         for (auto& subcontext : *subcontexts_) { | 
| Elliott Hughes | 579e682 | 2017-12-20 09:41:00 -0800 | [diff] [blame] | 1230 |             if (StartsWith(filename, subcontext.path_prefix())) { | 
| Tom Cherry | cb0f9bb | 2017-09-12 15:58:47 -0700 | [diff] [blame] | 1231 |                 restart_action_subcontext = &subcontext; | 
 | 1232 |                 break; | 
 | 1233 |             } | 
 | 1234 |         } | 
 | 1235 |     } | 
 | 1236 |  | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1237 |     std::vector<std::string> str_args(args.begin() + 2, args.end()); | 
| Tom Cherry | 40acb37 | 2018-08-01 13:41:12 -0700 | [diff] [blame] | 1238 |  | 
 | 1239 |     if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) { | 
 | 1240 |         if (str_args[0] == "/sbin/watchdogd") { | 
 | 1241 |             str_args[0] = "/system/bin/watchdogd"; | 
 | 1242 |         } | 
 | 1243 |     } | 
 | 1244 |  | 
| Tom Cherry | cb0f9bb | 2017-09-12 15:58:47 -0700 | [diff] [blame] | 1245 |     service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args); | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1246 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1247 | } | 
 | 1248 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1249 | Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) { | 
 | 1250 |     return service_ ? service_->ParseLine(std::move(args)) : Result<void>{}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1251 | } | 
 | 1252 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1253 | Result<void> ServiceParser::EndSection() { | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1254 |     if (service_) { | 
| Steven Moreland | 5e1bea3 | 2017-11-10 14:43:58 -0800 | [diff] [blame] | 1255 |         Service* old_service = service_list_->FindService(service_->name()); | 
 | 1256 |         if (old_service) { | 
| Steven Moreland | 6f5333a | 2017-11-13 15:31:54 -0800 | [diff] [blame] | 1257 |             if (!service_->is_override()) { | 
 | 1258 |                 return Error() << "ignored duplicate definition of service '" << service_->name() | 
 | 1259 |                                << "'"; | 
 | 1260 |             } | 
 | 1261 |  | 
| Jiyong Park | 80aa447 | 2018-11-12 12:08:41 +0900 | [diff] [blame] | 1262 |             if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) { | 
 | 1263 |                 return Error() << "cannot update a non-updatable service '" << service_->name() | 
 | 1264 |                                << "' with a config in APEX"; | 
 | 1265 |             } | 
 | 1266 |  | 
| Steven Moreland | 6f5333a | 2017-11-13 15:31:54 -0800 | [diff] [blame] | 1267 |             service_list_->RemoveService(*old_service); | 
 | 1268 |             old_service = nullptr; | 
| Steven Moreland | 5e1bea3 | 2017-11-10 14:43:58 -0800 | [diff] [blame] | 1269 |         } | 
 | 1270 |  | 
| Tom Cherry | 911b9b1 | 2017-07-27 16:20:58 -0700 | [diff] [blame] | 1271 |         service_list_->AddService(std::move(service_)); | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1272 |     } | 
| Steven Moreland | 7d0a5c3 | 2017-11-10 14:20:47 -0800 | [diff] [blame] | 1273 |  | 
| Tom Cherry | bbcbc2f | 2019-06-10 11:08:01 -0700 | [diff] [blame] | 1274 |     return {}; | 
| Tom Cherry | b734990 | 2015-08-26 11:43:36 -0700 | [diff] [blame] | 1275 | } | 
 | 1276 |  | 
 | 1277 | bool ServiceParser::IsValidName(const std::string& name) const { | 
| Elliott Hughes | b7788fd | 2017-02-28 09:54:36 -0800 | [diff] [blame] | 1278 |     // Property names can be any length, but may only contain certain characters. | 
 | 1279 |     // Property values can contain any characters, but may only be a certain length. | 
 | 1280 |     // (The latter restriction is needed because `start` and `stop` work by writing | 
 | 1281 |     // the service name to the "ctl.start" and "ctl.stop" properties.) | 
| Tom Cherry | de6bd50 | 2018-02-13 16:50:08 -0800 | [diff] [blame] | 1282 |     return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX; | 
| Tom Cherry | bac3299 | 2015-07-31 12:45:25 -0700 | [diff] [blame] | 1283 | } | 
| Tom Cherry | 81f5d3e | 2017-06-22 12:53:17 -0700 | [diff] [blame] | 1284 |  | 
 | 1285 | }  // namespace init | 
 | 1286 | }  // namespace android |