Merge "init: clarify a comment"
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 1d72c70..30d01a6 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -121,6 +121,34 @@
     ],
 }
 
+cc_library_static {
+    name: "libsnapshot_test_helpers",
+    defaults: ["libsnapshot_defaults"],
+    export_include_dirs: [
+        "include_test",
+    ],
+    srcs: [
+        "test_helpers.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.boot@1.1",
+        "libcrypto",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.boot@1.1",
+    ],
+    header_libs: [
+        "libstorage_literals_headers",
+    ],
+    export_header_lib_headers: [
+        "libstorage_literals_headers",
+    ],
+    static_libs: [
+        "libgtest",
+        "libgmock",
+    ],
+}
+
 cc_test {
     name: "libsnapshot_test",
     defaults: ["libsnapshot_defaults"],
@@ -144,6 +172,7 @@
         "libgmock",
         "liblp",
         "libsnapshot",
+        "libsnapshot_test_helpers",
         "libsparse",
         "libz",
     ],
diff --git a/fs_mgr/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
similarity index 100%
rename from fs_mgr/libsnapshot/test_helpers.h
rename to fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index eae6c35..9da3f05 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -18,9 +18,10 @@
 #include <liblp/builder.h>
 #include <liblp/property_fetcher.h>
 
+#include <libsnapshot/test_helpers.h>
+
 #include "dm_snapshot_internals.h"
 #include "partition_cow_creator.h"
-#include "test_helpers.h"
 #include "utility.h"
 
 using namespace android::fs_mgr;
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
index 4fd8759..337be4f 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
@@ -24,7 +24,7 @@
 #include <liblp/builder.h>
 #include <storage_literals/storage_literals.h>
 
-#include "test_helpers.h"
+#include <libsnapshot/test_helpers.h>
 
 using namespace android::storage_literals;
 using android::fs_mgr::LpMetadata;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 9e5fef3..ff943f2 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -38,7 +38,7 @@
 #include <storage_literals/storage_literals.h>
 
 #include <android/snapshot/snapshot.pb.h>
-#include "test_helpers.h"
+#include <libsnapshot/test_helpers.h>
 #include "utility.h"
 
 namespace android {
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 2d62347..f7f25af 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "test_helpers.h"
+#include <libsnapshot/test_helpers.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 6bf3997..62a19ab 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -360,57 +360,61 @@
     return {};
 }
 
-// mkdir <path> [mode] [owner] [group] [<option> ...]
-static Result<void> do_mkdir(const BuiltinArguments& args) {
-    auto options = ParseMkdir(args.args);
-    if (!options) return options.error();
+static Result<void> make_dir_with_options(const MkdirOptions& options) {
     std::string ref_basename;
-    if (options->ref_option == "ref") {
+    if (options.ref_option == "ref") {
         ref_basename = fscrypt_key_ref;
-    } else if (options->ref_option == "per_boot_ref") {
+    } else if (options.ref_option == "per_boot_ref") {
         ref_basename = fscrypt_key_per_boot_ref;
     } else {
-        return Error() << "Unknown key option: '" << options->ref_option << "'";
+        return Error() << "Unknown key option: '" << options.ref_option << "'";
     }
 
     struct stat mstat;
-    if (lstat(options->target.c_str(), &mstat) != 0) {
+    if (lstat(options.target.c_str(), &mstat) != 0) {
         if (errno != ENOENT) {
-            return ErrnoError() << "lstat() failed on " << options->target;
+            return ErrnoError() << "lstat() failed on " << options.target;
         }
-        if (!make_dir(options->target, options->mode)) {
-            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options->target;
+        if (!make_dir(options.target, options.mode)) {
+            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options.target;
         }
-        if (lstat(options->target.c_str(), &mstat) != 0) {
-            return ErrnoError() << "lstat() failed on new " << options->target;
+        if (lstat(options.target.c_str(), &mstat) != 0) {
+            return ErrnoError() << "lstat() failed on new " << options.target;
         }
     }
     if (!S_ISDIR(mstat.st_mode)) {
-        return Error() << "Not a directory on " << options->target;
+        return Error() << "Not a directory on " << options.target;
     }
-    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options->mode;
-    if ((options->uid != static_cast<uid_t>(-1) && options->uid != mstat.st_uid) ||
-        (options->gid != static_cast<gid_t>(-1) && options->gid != mstat.st_gid)) {
-        if (lchown(options->target.c_str(), options->uid, options->gid) == -1) {
-            return ErrnoError() << "lchown failed on " << options->target;
+    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options.mode;
+    if ((options.uid != static_cast<uid_t>(-1) && options.uid != mstat.st_uid) ||
+        (options.gid != static_cast<gid_t>(-1) && options.gid != mstat.st_gid)) {
+        if (lchown(options.target.c_str(), options.uid, options.gid) == -1) {
+            return ErrnoError() << "lchown failed on " << options.target;
         }
         // chown may have cleared S_ISUID and S_ISGID, chmod again
         needs_chmod = true;
     }
     if (needs_chmod) {
-        if (fchmodat(AT_FDCWD, options->target.c_str(), options->mode, AT_SYMLINK_NOFOLLOW) == -1) {
-            return ErrnoError() << "fchmodat() failed on " << options->target;
+        if (fchmodat(AT_FDCWD, options.target.c_str(), options.mode, AT_SYMLINK_NOFOLLOW) == -1) {
+            return ErrnoError() << "fchmodat() failed on " << options.target;
         }
     }
     if (fscrypt_is_native()) {
-        if (!FscryptSetDirectoryPolicy(ref_basename, options->fscrypt_action, options->target)) {
+        if (!FscryptSetDirectoryPolicy(ref_basename, options.fscrypt_action, options.target)) {
             return reboot_into_recovery(
-                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options->target});
+                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options.target});
         }
     }
     return {};
 }
 
+// mkdir <path> [mode] [owner] [group] [<option> ...]
+static Result<void> do_mkdir(const BuiltinArguments& args) {
+    auto options = ParseMkdir(args.args);
+    if (!options) return options.error();
+    return make_dir_with_options(*options);
+}
+
 /* umount <path> */
 static Result<void> do_umount(const BuiltinArguments& args) {
     if (umount(args[1].c_str()) < 0) {
@@ -1172,7 +1176,7 @@
     return {};
 }
 
-static Result<void> do_parse_apex_configs(const BuiltinArguments& args) {
+static Result<void> parse_apex_configs() {
     glob_t glob_result;
     static constexpr char glob_pattern[] = "/apex/*/etc/*.rc";
     const int ret = glob(glob_pattern, GLOB_MARK, nullptr, &glob_result);
@@ -1211,6 +1215,45 @@
     }
 }
 
+/*
+ * Creates a directory under /data/misc/apexdata/ for each APEX.
+ */
+static Result<void> create_apex_data_dirs() {
+    auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/apex"), closedir);
+    if (!dirp) {
+        return ErrnoError() << "Unable to open apex directory";
+    }
+    struct dirent* entry;
+    while ((entry = readdir(dirp.get())) != nullptr) {
+        if (entry->d_type != DT_DIR) continue;
+
+        const char* name = entry->d_name;
+        // skip any starting with "."
+        if (name[0] == '.') continue;
+
+        if (strchr(name, '@') != nullptr) continue;
+
+        auto path = "/data/misc/apexdata/" + std::string(name);
+        auto system_uid = DecodeUid("system");
+        auto options =
+                MkdirOptions{path, 0700, *system_uid, *system_uid, FscryptAction::kNone, "ref"};
+        make_dir_with_options(options);
+    }
+    return {};
+}
+
+static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
+    auto create_dirs = create_apex_data_dirs();
+    if (!create_dirs) {
+        return create_dirs.error();
+    }
+    auto parse_configs = parse_apex_configs();
+    if (!parse_configs) {
+        return parse_configs.error();
+    }
+    return {};
+}
+
 static Result<void> do_enter_default_mount_ns(const BuiltinArguments& args) {
     if (SwitchToDefaultMountNamespace()) {
         return {};
@@ -1271,7 +1314,7 @@
         // mount and umount are run in the same context as mount_all for symmetry.
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
-        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
+        {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"umount_all",              {1,     1,    {false,  do_umount_all}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 3b5a41d..1758cfa 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -198,7 +198,7 @@
     // Note in this case, that the source and destination directories are the same, so only one
     // fsync() is required.
     auto dir = Dirname(persistent_property_filename);
-    auto dir_fd = unique_fd{open(dir.c_str(), O_DIRECTORY | O_RDONLY)};
+    auto dir_fd = unique_fd{open(dir.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC)};
     if (dir_fd < 0) {
         return ErrnoError() << "Unable to open persistent properties directory for fsync()";
     }
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3fc5e5d..7b18438 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -104,11 +104,6 @@
     bool debug_ = false;
 };
 
-// logd prefixes records with a length field
-#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
-
-enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
-
 #ifndef F2FS_IOC_SET_PIN_FILE
 #define F2FS_IOCTL_MAGIC       0xf5
 #define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index e2ecad4..88b6da4 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -579,6 +579,8 @@
     mkdir /data/misc/profman 0770 system shell
     mkdir /data/misc/gcov 0770 root root
     mkdir /data/misc/installd 0700 root root
+    mkdir /data/misc/apexdata 0700 root root
+    mkdir /data/misc/apexrollback 0700 root root
 
     mkdir /data/preloads 0775 system system encryption=None
 
@@ -668,7 +670,8 @@
 
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
-    parse_apex_configs
+    perform_apex_config
+
     exec_start derive_sdk
 
     init_user0