Merge "fastbootd: exporting CPU ABI info"
diff --git a/init/Android.bp b/init/Android.bp
index d939fcc..c7021c3 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -185,9 +185,11 @@
     static_libs: ["libinit"],
     required: [
         "e2fsdroid",
+        "init.rc",
         "mke2fs",
         "sload_f2fs",
         "make_f2fs",
+        "ueventd.rc",
     ],
     srcs: ["main.cpp"],
     symlinks: ["ueventd"],
@@ -281,6 +283,8 @@
     static_libs: [
         "libbase",
         "libselinux",
+        "libpropertyinfoserializer",
+        "libpropertyinfoparser",
     ],
     whole_static_libs: ["libcap"],
     shared_libs: [
@@ -304,6 +308,7 @@
         "host_import_parser.cpp",
         "host_init_verifier.cpp",
         "parser.cpp",
+        "property_type.cpp",
         "rlimit_parser.cpp",
         "tokenizer.cpp",
         "service.cpp",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5ee928e..a55514b 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -140,14 +140,7 @@
     if (!write_bootloader_message(options, &err)) {
         return Error() << "Failed to set bootloader message: " << err;
     }
-    // This function should only be reached from init and not from vendor_init, and we want to
-    // immediately trigger reboot instead of relaying through property_service.  Older devices may
-    // still have paths that reach here from vendor_init, so we keep the property_set as a fallback.
-    if (getpid() == 1) {
-        TriggerShutdown("reboot,recovery");
-    } else {
-        property_set("sys.powerctl", "reboot,recovery");
-    }
+    trigger_shutdown("reboot,recovery");
     return {};
 }
 
@@ -554,7 +547,7 @@
             // support userdata remount on FDE devices, this should never been triggered. Time to
             // panic!
             LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
-            TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
+            trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
         }
         ActionManager::GetInstance().QueueEventTrigger("encrypt");
         return {};
@@ -564,7 +557,7 @@
             // don't support userdata remount on FDE devices, this should never been triggered.
             // Time to panic!
             LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
-            TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
+            trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "block");
@@ -1148,7 +1141,7 @@
     }
     // TODO(b/135984674): check that fstab contains /data.
     if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
-        TriggerShutdown("reboot,mount-userdata-failed");
+        trigger_shutdown("reboot,mount-userdata-failed");
     }
     if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result) {
         return Error() << "queue_fs_event() failed: " << result.error();
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index 9d23921..bef6966 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -29,7 +29,9 @@
 #include <android-base/strings.h>
 
 #include "builtin_arguments.h"
+#include "host_init_verifier.h"
 #include "interface_utils.h"
+#include "property_type.h"
 #include "rlimit_parser.h"
 #include "service.h"
 #include "util.h"
@@ -171,6 +173,15 @@
                        << "' from init; use the restorecon builtin directly";
     }
 
+    const char* target_context = nullptr;
+    const char* type = nullptr;
+    property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
+
+    if (!CheckType(type, value)) {
+        return Error() << "Property type check failed, value doesn't match expected type '"
+                       << (type ?: "(null)") << "'";
+    }
+
     return {};
 }
 
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 9b33a1c..30d3129 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -35,11 +35,6 @@
 namespace android {
 namespace init {
 
-// init.h
-inline void TriggerShutdown(const std::string&) {
-    abort();
-}
-
 // property_service.h
 inline bool CanReadProperty(const std::string&, const std::string&) {
     return true;
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 522709e..3acc3cc 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+#include "host_init_verifier.h"
+
 #include <errno.h>
 #include <getopt.h>
 #include <pwd.h>
@@ -31,6 +33,7 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <hidl/metadata.h>
+#include <property_info_serializer/property_info_serializer.h>
 
 #include "action.h"
 #include "action_manager.h"
@@ -53,6 +56,10 @@
 using android::base::ParseInt;
 using android::base::ReadFileToString;
 using android::base::Split;
+using android::properties::BuildTrie;
+using android::properties::ParsePropertyInfoFile;
+using android::properties::PropertyInfoArea;
+using android::properties::PropertyInfoEntry;
 
 static std::vector<std::string> passwd_files;
 
@@ -143,11 +150,12 @@
 #include "generated_stub_builtin_function_map.h"
 
 void PrintUsage() {
-    std::cout << "usage: host_init_verifier [-p FILE] <init rc file>\n"
+    std::cout << "usage: host_init_verifier [options] <init rc file>\n"
                  "\n"
                  "Tests an init script for correctness\n"
                  "\n"
                  "-p FILE\tSearch this passwd file for users and groups\n"
+                 "--property_contexts=FILE\t Use this file for property_contexts\n"
               << std::endl;
 }
 
@@ -172,23 +180,53 @@
     return result;
 }
 
+const PropertyInfoArea* property_info_area;
+
+void HandlePropertyContexts(const std::string& filename,
+                            std::vector<PropertyInfoEntry>* property_infos) {
+    auto file_contents = std::string();
+    if (!ReadFileToString(filename, &file_contents)) {
+        PLOG(ERROR) << "Could not read properties from '" << filename << "'";
+        exit(EXIT_FAILURE);
+    }
+
+    auto errors = std::vector<std::string>{};
+    ParsePropertyInfoFile(file_contents, property_infos, &errors);
+    for (const auto& error : errors) {
+        LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
+    }
+    if (!errors.empty()) {
+        exit(EXIT_FAILURE);
+    }
+}
+
 int main(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
+    auto property_infos = std::vector<PropertyInfoEntry>();
+
     while (true) {
+        static const char kPropertyContexts[] = "property-contexts=";
         static const struct option long_options[] = {
                 {"help", no_argument, nullptr, 'h'},
+                {kPropertyContexts, required_argument, nullptr, 0},
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:", long_options, nullptr);
+        int option_index;
+        int arg = getopt_long(argc, argv, "p:", long_options, &option_index);
 
         if (arg == -1) {
             break;
         }
 
         switch (arg) {
+            case 0:
+                if (long_options[option_index].name == kPropertyContexts) {
+                    HandlePropertyContexts(optarg, &property_infos);
+                }
+                break;
             case 'h':
                 PrintUsage();
                 return EXIT_FAILURE;
@@ -216,6 +254,16 @@
     }
     SetKnownInterfaces(*interface_inheritance_hierarchy_map);
 
+    std::string serialized_contexts;
+    std::string trie_error;
+    if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
+                   &trie_error)) {
+        LOG(ERROR) << "Unable to serialize property contexts: " << trie_error;
+        return EXIT_FAILURE;
+    }
+
+    property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_contexts.c_str());
+
     const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
     Action::set_function_map(&function_map);
     ActionManager& am = ActionManager::GetInstance();
diff --git a/init/host_init_verifier.h b/init/host_init_verifier.h
new file mode 100644
index 0000000..5d24f2a
--- /dev/null
+++ b/init/host_init_verifier.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <property_info_parser/property_info_parser.h>
+
+namespace android {
+namespace init {
+
+extern const android::properties::PropertyInfoArea* property_info_area;
+
+}  // namespace init
+}  // namespace android
diff --git a/init/init.cpp b/init/init.cpp
index 6ea2d00..8e2da59 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -136,7 +136,7 @@
 
     std::string bootscript = GetProperty("ro.boot.init_rc", "");
     if (bootscript.empty()) {
-        parser.ParseConfig("/init.rc");
+        parser.ParseConfig("/system/etc/init/hw/init.rc");
         if (!parser.ParseConfig("/system/etc/init")) {
             late_import_paths.emplace_back("/system/etc/init");
         }
@@ -180,7 +180,7 @@
     waiting_for_prop.reset();
 }
 
-void TriggerShutdown(const std::string& command) {
+static void TriggerShutdown(const std::string& command) {
     // We can't call HandlePowerctlMessage() directly in this function,
     // because it modifies the contents of the action queue, which can cause the action queue
     // to get into a bad state if this function is called from a command being executed by the
@@ -681,6 +681,8 @@
 
     boot_clock::time_point start_time = boot_clock::now();
 
+    trigger_shutdown = TriggerShutdown;
+
     SetStdioToDevNull(argv);
     InitKernelLogging(argv);
     LOG(INFO) << "init second stage started!";
diff --git a/init/init.h b/init/init.h
index d884a94..0805940 100644
--- a/init/init.h
+++ b/init/init.h
@@ -31,8 +31,6 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
 Parser CreateServiceOnlyParser(ServiceList& service_list);
 
-void TriggerShutdown(const std::string& command);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 3baaf7c..7d707cc 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -478,7 +478,7 @@
         return PROP_ERROR_PERMISSION_DENIED;
     }
 
-    if (type == nullptr || !CheckType(type, value)) {
+    if (!CheckType(type, value)) {
         *error = StringPrintf("Property type check failed, value doesn't match expected type '%s'",
                               (type ?: "(null)"));
         return PROP_ERROR_INVALID_VALUE;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 4a16969..64ec1fb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -731,7 +731,7 @@
     auto guard = android::base::make_scope_guard([] {
         // Leave shutdown so that we can handle a full reboot.
         LeaveShutdown();
-        TriggerShutdown("reboot,abort-userspace-reboot");
+        trigger_shutdown("reboot,abort-userspace-reboot");
     });
     // Triggering userspace-reboot-requested will result in a bunch of set_prop
     // actions. We should make sure, that all of them are propagated before
diff --git a/init/service.cpp b/init/service.cpp
index f8e98a2..574ff52 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -43,7 +43,6 @@
 #if defined(__ANDROID__)
 #include <ApexProperties.sysprop.h>
 
-#include "init.h"
 #include "mount_namespace.h"
 #include "property_service.h"
 #else
@@ -260,7 +259,7 @@
 
     if ((siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) && on_failure_reboot_target_) {
         LOG(ERROR) << "Service with 'reboot_on_failure' option failed, shutting down system.";
-        TriggerShutdown(*on_failure_reboot_target_);
+        trigger_shutdown(*on_failure_reboot_target_);
     }
 
     if (flags_ & SVC_EXEC) UnSetExec();
@@ -340,7 +339,7 @@
 Result<void> Service::ExecStart() {
     auto reboot_on_failure = make_scope_guard([this] {
         if (on_failure_reboot_target_) {
-            TriggerShutdown(*on_failure_reboot_target_);
+            trigger_shutdown(*on_failure_reboot_target_);
         }
     });
 
@@ -371,7 +370,7 @@
 Result<void> Service::Start() {
     auto reboot_on_failure = make_scope_guard([this] {
         if (on_failure_reboot_target_) {
-            TriggerShutdown(*on_failure_reboot_target_);
+            trigger_shutdown(*on_failure_reboot_target_);
         }
     });
 
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 79fc372..e55265b 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -51,6 +51,8 @@
 namespace init {
 namespace {
 
+std::string shutdown_command;
+
 class SubcontextProcess {
   public:
     SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
@@ -153,6 +155,11 @@
                            << subcontext_command.command_case();
         }
 
+        if (!shutdown_command.empty()) {
+            reply.set_trigger_shutdown(shutdown_command);
+            shutdown_command.clear();
+        }
+
         if (auto result = SendMessage(init_fd_, reply); !result) {
             LOG(FATAL) << "Failed to send message to init: " << result.error();
         }
@@ -174,6 +181,8 @@
         return 0;
     };
 
+    trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
+
     auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
     subcontext_process.MainLoop();
     return 0;
@@ -254,6 +263,11 @@
         Restart();
         return Error() << "Unable to parse message from subcontext";
     }
+
+    if (subcontext_reply.has_trigger_shutdown()) {
+        trigger_shutdown(subcontext_reply.trigger_shutdown());
+    }
+
     return subcontext_reply;
 }
 
diff --git a/init/subcontext.proto b/init/subcontext.proto
index e68115e..068c7ce 100644
--- a/init/subcontext.proto
+++ b/init/subcontext.proto
@@ -38,4 +38,6 @@
         Failure failure = 2;
         ExpandArgsReply expand_args_reply = 3;
     }
+
+    optional string trigger_shutdown = 4;
 }
\ No newline at end of file
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 9cac35e..9c1a788 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -26,6 +26,7 @@
 #include <selinux/selinux.h>
 
 #include "builtin_arguments.h"
+#include "util.h"
 
 using namespace std::literals;
 
@@ -142,6 +143,18 @@
     });
 }
 
+TEST(subcontext, TriggerShutdown) {
+    static constexpr const char kTestShutdownCommand[] = "reboot,test-shutdown-command";
+    static std::string trigger_shutdown_command;
+    trigger_shutdown = [](const std::string& command) { trigger_shutdown_command = command; };
+    RunTest([](auto& subcontext, auto& context_string) {
+        auto result = subcontext.Execute(
+                std::vector<std::string>{"trigger_shutdown", kTestShutdownCommand});
+        ASSERT_TRUE(result);
+    });
+    EXPECT_EQ(kTestShutdownCommand, trigger_shutdown_command);
+}
+
 TEST(subcontext, ExpandArgs) {
     RunTest([](auto& subcontext, auto& context_string) {
         auto args = std::vector<std::string>{
@@ -207,6 +220,11 @@
         return Error() << args.context;
     };
 
+    auto do_trigger_shutdown = [](const BuiltinArguments& args) -> Result<void> {
+        trigger_shutdown(args[1]);
+        return {};
+    };
+
     // clang-format off
     BuiltinFunctionMap test_function_map = {
         {"return_pids_as_error",        {0,     0,      {true,  do_return_pids_as_error}}},
@@ -216,6 +234,7 @@
         {"cause_log_fatal",             {0,     0,      {true,  do_cause_log_fatal}}},
         {"generate_sane_error",         {0,     0,      {true,  do_generate_sane_error}}},
         {"return_context_as_error",     {0,     0,      {true,  do_return_context_as_error}}},
+        {"trigger_shutdown",            {1,     1,      {true,  do_trigger_shutdown}}},
     };
     // clang-format on
     return test_function_map;
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 416d942..d8d9b36 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -100,7 +100,7 @@
     int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
     if (n <= 0) {
         if (errno != EAGAIN && errno != EWOULDBLOCK) {
-            LOG(ERROR) << "Error reading from Uevent Fd";
+            PLOG(ERROR) << "Error reading from Uevent Fd";
         }
         return false;
     }
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 59f91ee..d2b503b 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -288,7 +288,7 @@
     // TODO: cleanup platform ueventd.rc to remove vendor specific device node entries (b/34968103)
     auto hardware = android::base::GetProperty("ro.hardware", "");
 
-    auto ueventd_configuration = ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc",
+    auto ueventd_configuration = ParseConfig({"/system/etc/ueventd.rc", "/vendor/ueventd.rc",
                                               "/odm/ueventd.rc", "/ueventd." + hardware + ".rc"});
 
     uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
diff --git a/init/util.cpp b/init/util.cpp
index ada9e78..e5254dd 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -61,6 +61,8 @@
 
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
 
+void (*trigger_shutdown)(const std::string& command) = nullptr;
+
 // DecodeUid() - decodes and returns the given string, which can be either the
 // numeric or name representation, into the integer uid or gid.
 Result<uid_t> DecodeUid(const std::string& name) {
diff --git a/init/util.h b/init/util.h
index 3d81d72..9d89ed7 100644
--- a/init/util.h
+++ b/init/util.h
@@ -35,6 +35,8 @@
 
 static const char kColdBootDoneProp[] = "ro.cold_boot_done";
 
+extern void (*trigger_shutdown)(const std::string& command);
+
 Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
                          gid_t gid, const std::string& socketcon);
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 88e1bdb..334364e 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -197,7 +197,10 @@
 
 cc_defaults {
     name: "libcutils_test_default",
-    srcs: ["sockets_test.cpp"],
+    srcs: [
+        "native_handle_test.cpp",
+        "sockets_test.cpp",
+    ],
 
     target: {
         android: {
diff --git a/libcutils/native_handle.cpp b/libcutils/native_handle.cpp
index b409e5b..5804ab1 100644
--- a/libcutils/native_handle.cpp
+++ b/libcutils/native_handle.cpp
@@ -81,6 +81,8 @@
 }
 
 int native_handle_close(const native_handle_t* h) {
+    if (!h) return 0;
+
     if (h->version != sizeof(native_handle_t)) return -EINVAL;
 
     int saved_errno = errno;
diff --git a/libcutils/native_handle_test.cpp b/libcutils/native_handle_test.cpp
new file mode 100644
index 0000000..c1e2f0b
--- /dev/null
+++ b/libcutils/native_handle_test.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <cutils/native_handle.h>
+
+#include <gtest/gtest.h>
+
+TEST(native_handle, native_handle_delete) {
+    ASSERT_EQ(0, native_handle_delete(nullptr));
+}
+
+TEST(native_handle, native_handle_close) {
+    ASSERT_EQ(0, native_handle_close(nullptr));
+}
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index 721de7c..bf244d2 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -60,7 +60,7 @@
     struct ucred* cred;
 
     *uid = -1;
-    ssize_t n = recvmsg(socket, &hdr, 0);
+    ssize_t n = TEMP_FAILURE_RETRY(recvmsg(socket, &hdr, 0));
     if (n <= 0) {
         return n;
     }
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 5871a63..0341902 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -39,6 +39,13 @@
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
+    },
+    {
+      "Controller": "freezer",
+      "Path": "/dev/freezer",
+      "Mode": "0755",
+      "UID": "system",
+      "GID": "system"
     }
   ],
   "Cgroups2": {
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 608f007..3f3dbd7 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -67,6 +67,32 @@
       ]
     },
     {
+      "Name": "Frozen",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "freezer",
+            "Path": "frozen"
+          }
+        }
+      ]
+    },
+    {
+      "Name": "Unfrozen",
+      "Actions": [
+        {
+          "Name": "JoinCgroup",
+          "Params":
+          {
+            "Controller": "freezer",
+            "Path": ""
+          }
+        }
+      ]
+    },
+    {
       "Name": "NormalPerformance",
       "Actions": [
         {
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 81f8c0f..56f594a 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -111,7 +111,8 @@
 
 static float CompressionRatio(int64_t uncompressed, int64_t compressed) {
   if (uncompressed == 0) return 0;
-  return static_cast<float>(100LL * (uncompressed - compressed)) / uncompressed;
+  return static_cast<float>(100LL * (uncompressed - compressed)) /
+         static_cast<float>(uncompressed);
 }
 
 static void MaybeShowHeader(ZipArchiveHandle zah) {
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
new file mode 100644
index 0000000..96b5e0d
--- /dev/null
+++ b/rootdir/Android.bp
@@ -0,0 +1,26 @@
+// Copyright 2019 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.
+
+prebuilt_etc {
+    name: "init.rc",
+    src: "init.rc",
+    sub_dir: "init/hw",
+    required: ["fsverity_init"],
+}
+
+prebuilt_etc {
+    name: "ueventd.rc",
+    src: "ueventd.rc",
+    recovery_available: true,
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 19f117f..994d9ae 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -1,22 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 
 #######################################
-# init.rc
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := init.rc
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
-LOCAL_REQUIRED_MODULES := fsverity_init
-
-# The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT.
-# Since init.rc is required for init and satisfies that requirement, we hijack it to create the symlink.
-LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
-
-include $(BUILD_PREBUILT)
-
-#######################################
 # init-debug.rc
 include $(CLEAR_VARS)
 
@@ -148,6 +132,10 @@
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/postinstall
 endif
 
+# The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT.
+# Since init.environ.rc is required for init and satisfies that requirement, we hijack it to create the symlink.
+LOCAL_POST_INSTALL_CMD += ; ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
+
 include $(BUILD_SYSTEM)/base_rules.mk
 
 $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0827247..674b737 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -5,11 +5,11 @@
 #
 
 import /init.environ.rc
-import /init.usb.rc
+import /system/etc/init/hw/init.usb.rc
 import /init.${ro.hardware}.rc
 import /vendor/etc/init/hw/init.${ro.hardware}.rc
-import /init.usb.configfs.rc
-import /init.${ro.zygote}.rc
+import /system/etc/init/hw/init.usb.configfs.rc
+import /system/etc/init/hw/init.${ro.zygote}.rc
 
 # Cgroups are mounted right before early-init using list from /etc/cgroups.json
 on early-init
@@ -283,6 +283,16 @@
     chmod 0664 /dev/cpuset/restricted/tasks
     chmod 0664 /dev/cpuset/tasks
 
+    # freezer cgroup entries
+    mkdir /dev/freezer/frozen
+    write /dev/freezer/frozen/freezer.state FROZEN
+    chown system system /dev/freezer/cgroup.procs
+    chown system system /dev/freezer/frozen
+    chown system system /dev/freezer/frozen/freezer.state
+    chown system system /dev/freezer/frozen/cgroup.procs
+
+    chmod 0444 /dev/freezer/frozen/freezer.state
+
     # make the PSI monitor accessible to others
     chown system system /proc/pressure/memory
     chmod 0664 /proc/pressure/memory