Merge "Reject services that are both critical and oneshot" into rvc-dev
diff --git a/init/init_test.cpp b/init/init_test.cpp
index caf3e03..07b4724 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -239,6 +239,28 @@
     EXPECT_EQ(6, num_executed);
 }
 
+TEST(init, RejectsCriticalAndOneshotService) {
+    std::string init_script =
+            R"init(
+service A something
+  class first
+  critical
+  oneshot
+)init";
+
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    ASSERT_TRUE(android::base::WriteStringToFd(init_script, tf.fd));
+
+    ServiceList service_list;
+    Parser parser;
+    parser.AddSectionParser("service",
+                            std::make_unique<ServiceParser>(&service_list, nullptr, std::nullopt));
+
+    ASSERT_TRUE(parser.ParseConfig(tf.path));
+    ASSERT_EQ(1u, parser.parse_error_count());
+}
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 560f693..c54ed71 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -598,6 +598,13 @@
         }
     }
 
+    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
+        if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) {
+            return Error() << "service '" << service_->name()
+                           << "' can't be both critical and oneshot";
+        }
+    }
+
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {