Apply the whitelist of actionable system properties

This whitelist will be applied only when
ro.actionable_compatible_property.enabled is true.

Bug: 38146102
Test: tested on walleye with ro.actionable_compatible_property.enabled=true
Change-Id: Ifd7211396b53e50a06d79e7c67224e2b38ef7c9d
diff --git a/init/action.cpp b/init/action.cpp
index 16ecdcd..ba03e66 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,6 +21,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 
+#include "stable_properties.h"
 #include "util.h"
 
 using android::base::Join;
@@ -134,6 +135,25 @@
     }
 }
 
+static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+    static bool enabled =
+        android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+    if (subcontext == nullptr || !enabled) {
+        return true;
+    }
+
+    if (kExportedActionableProperties.count(prop_name) == 1) {
+        return true;
+    }
+    for (const auto& prefix : kPartnerPrefixes) {
+        if (android::base::StartsWith(prop_name, prefix)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
     const static std::string prop_str("property:");
     std::string prop_name(trigger.substr(prop_str.length()));
@@ -145,6 +165,10 @@
     std::string prop_value(prop_name.substr(equal_pos + 1));
     prop_name.erase(equal_pos);
 
+    if (!IsActionableProperty(subcontext_, prop_name)) {
+        return Error() << "unexported property tigger found: " << prop_name;
+    }
+
     if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
         return Error() << "multiple property triggers found for same property";
     }
diff --git a/init/stable_properties.h b/init/stable_properties.h
new file mode 100644
index 0000000..8219838
--- /dev/null
+++ b/init/stable_properties.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_STABLE_PROPERTIES_H
+#define _INIT_STABLE_PROPERTIES_H
+
+#include <set>
+#include <string>
+
+namespace android {
+namespace init {
+
+static constexpr const char* kPartnerPrefixes[] = {
+    "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
+    "init.svc.odm.",    "ro.odm.",    "persist.odm.",    "odm.",
+};
+
+static const std::set<std::string> kExportedActionableProperties = {
+    "init.svc.zygote",         "persist.bluetooth.btsnoopenable",
+    "persist.sys.crash_rcu",   "persist.sys.zram_enabled",
+    "ro.boot.revision",        "ro.bootmode",
+    "ro.build.type",           "sys.boot_completed",
+    "sys.retaildemo.enabled",  "sys.shutdown.requested",
+    "sys.usb.config",          "sys.usb.configfs",
+    "sys.usb.ffs.mtp.ready",   "sys.usb.ffs.ready",
+    "sys.user.0.ce_available", "sys.vdso",
+    "vts.native_server.on",
+};
+
+}  // namespace init
+}  // namespace android
+
+#endif