Merge "Clear the warm_reset flag after boot is successful"
diff --git a/Android.bp b/Android.bp
index 452746c..8d88e5f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -54,6 +54,7 @@
"libf2fs_sparseblock",
"libhardware",
"libhardware_legacy",
+ "libincfs",
"libhidlbase",
"libkeymaster4support",
"libkeyutils",
@@ -78,9 +79,15 @@
],
aidl: {
local_include_dirs: ["binder"],
- include_dirs: ["frameworks/native/aidl/binder"],
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ "frameworks/base/core/java/android/os/incremental",
+ ],
export_aidl_headers: true,
},
+ whole_static_libs: [
+ "libincremental_aidl-cpp",
+ ],
}
cc_library_headers {
diff --git a/OWNERS b/OWNERS
index 7779c20..bab0ef6 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,4 +3,4 @@
paullawrence@google.com
ebiggers@google.com
drosen@google.com
-
+zezeozue@google.com
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index f17f59f..cc32820 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -28,6 +28,7 @@
#include "FsCrypt.h"
#include "MetadataCrypt.h"
#include "cryptfs.h"
+#include "incfs_ndk.h"
#include <fstream>
#include <thread>
@@ -915,5 +916,38 @@
return ok();
}
+binder::Status VoldNativeService::incFsVersion(int32_t* _aidl_return) {
+ *_aidl_return = IncFs_Version();
+ return ok();
+}
+
+binder::Status VoldNativeService::mountIncFs(
+ const std::string& imagePath, const std::string& targetDir, int32_t flags,
+ ::android::os::incremental::IncrementalFileSystemControlParcel* _aidl_return) {
+ auto result = IncFs_Mount(imagePath.c_str(), targetDir.c_str(), flags,
+ INCFS_DEFAULT_READ_TIMEOUT_MS, 0777);
+ if (result.cmdFd < 0) {
+ return translate(result.cmdFd);
+ }
+ LOG(INFO) << "VoldNativeService::mountIncFs: everything is fine! " << result.cmdFd << "/"
+ << result.logFd;
+ using ParcelFileDescriptor = ::android::os::ParcelFileDescriptor;
+ using unique_fd = ::android::base::unique_fd;
+ _aidl_return->cmd = std::make_unique<ParcelFileDescriptor>(unique_fd(result.cmdFd));
+ if (result.logFd >= 0) {
+ _aidl_return->log = std::make_unique<ParcelFileDescriptor>(unique_fd(result.logFd));
+ }
+ return ok();
+}
+
+binder::Status VoldNativeService::unmountIncFs(const std::string& dir) {
+ return translate(IncFs_Unmount(dir.c_str()));
+}
+
+binder::Status VoldNativeService::bindMount(const std::string& sourceDir,
+ const std::string& targetDir) {
+ return translate(IncFs_BindMount(sourceDir.c_str(), targetDir.c_str()));
+}
+
} // namespace vold
} // namespace android
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 13137c5..0718263 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -141,6 +141,13 @@
binder::Status supportsBlockCheckpoint(bool* _aidl_return);
binder::Status supportsFileCheckpoint(bool* _aidl_return);
binder::Status resetCheckpoint();
+
+ binder::Status incFsVersion(int32_t* _aidl_return) override;
+ binder::Status mountIncFs(
+ const std::string& imagePath, const std::string& targetDir, int32_t flags,
+ ::android::os::incremental::IncrementalFileSystemControlParcel* _aidl_return) override;
+ binder::Status unmountIncFs(const std::string& dir) override;
+ binder::Status bindMount(const std::string& sourceDir, const std::string& targetDir) override;
};
} // namespace vold
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 8e5c53d..681e9dc 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -16,6 +16,7 @@
package android.os;
+import android.os.incremental.IncrementalFileSystemControlParcel;
import android.os.IVoldListener;
import android.os.IVoldTaskListener;
@@ -125,6 +126,11 @@
FileDescriptor openAppFuseFile(int uid, int mountId, int fileId, int flags);
+ int incFsVersion();
+ IncrementalFileSystemControlParcel mountIncFs(@utf8InCpp String imagePath, @utf8InCpp String targetDir, int flags);
+ void unmountIncFs(@utf8InCpp String dir);
+ void bindMount(@utf8InCpp String sourceDir, @utf8InCpp String targetDir);
+
const int ENCRYPTION_FLAG_NO_UI = 4;
const int ENCRYPTION_STATE_NONE = 1;
diff --git a/tests/Android.bp b/tests/Android.bp
index a070178..4731d0a 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -6,7 +6,6 @@
],
srcs: [
- "CryptfsScryptHidlizationEquivalence_test.cpp",
"Utils_test.cpp",
"cryptfs_test.cpp",
],
diff --git a/tests/CryptfsScryptHidlizationEquivalence_test.cpp b/tests/CryptfsScryptHidlizationEquivalence_test.cpp
deleted file mode 100644
index 72170e3..0000000
--- a/tests/CryptfsScryptHidlizationEquivalence_test.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-**
-** Copyright 2017, 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.
-*/
-
-#define LOG_TAG "scrypt_test"
-#include <log/log.h>
-
-#include <gtest/gtest.h>
-#include <hardware/keymaster0.h>
-#include <hardware/keymaster1.h>
-#include <cstring>
-
-#include "../Keymaster.h"
-#include "../cryptfs.h"
-
-#ifdef CONFIG_HW_DISK_ENCRYPTION
-#include "cryptfs_hw.h"
-#endif
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
-/* Maximum allowed keymaster blob size. */
-#define KEYMASTER_BLOB_SIZE 2048
-
-/* Key Derivation Function algorithms */
-#define KDF_PBKDF2 1
-#define KDF_SCRYPT 2
-/* Algorithms 3 & 4 deprecated before shipping outside of google, so removed */
-#define KDF_SCRYPT_KEYMASTER 5
-
-#define KEY_LEN_BYTES 16
-
-#define DEFAULT_PASSWORD "default_password"
-
-#define RSA_KEY_SIZE 2048
-#define RSA_KEY_SIZE_BYTES (RSA_KEY_SIZE / 8)
-#define RSA_EXPONENT 0x10001
-#define KEYMASTER_CRYPTFS_RATE_LIMIT 1 // Maximum one try per second
-
-static int keymaster_init(keymaster0_device_t** keymaster0_dev,
- keymaster1_device_t** keymaster1_dev) {
- int rc;
-
- const hw_module_t* mod;
- rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
- if (rc) {
- ALOGE("could not find any keystore module");
- goto err;
- }
-
- SLOGI("keymaster module name is %s", mod->name);
- SLOGI("keymaster version is %d", mod->module_api_version);
-
- *keymaster0_dev = NULL;
- *keymaster1_dev = NULL;
- if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
- SLOGI("Found keymaster1 module, using keymaster1 API.");
- rc = keymaster1_open(mod, keymaster1_dev);
- } else {
- SLOGI("Found keymaster0 module, using keymaster0 API.");
- rc = keymaster0_open(mod, keymaster0_dev);
- }
-
- if (rc) {
- ALOGE("could not open keymaster device in %s (%s)", KEYSTORE_HARDWARE_MODULE_ID,
- strerror(-rc));
- goto err;
- }
-
- return 0;
-
-err:
- *keymaster0_dev = NULL;
- *keymaster1_dev = NULL;
- return rc;
-}
-
-/* Should we use keymaster? */
-static int keymaster_check_compatibility_old() {
- keymaster0_device_t* keymaster0_dev = 0;
- keymaster1_device_t* keymaster1_dev = 0;
- int rc = 0;
-
- if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
- SLOGE("Failed to init keymaster");
- rc = -1;
- goto out;
- }
-
- if (keymaster1_dev) {
- rc = 1;
- goto out;
- }
-
- if (!keymaster0_dev || !keymaster0_dev->common.module) {
- rc = -1;
- goto out;
- }
-
- // TODO(swillden): Check to see if there's any reason to require v0.3. I think v0.1 and v0.2
- // should work.
- if (keymaster0_dev->common.module->module_api_version < KEYMASTER_MODULE_API_VERSION_0_3) {
- rc = 0;
- goto out;
- }
-
- if (!(keymaster0_dev->flags & KEYMASTER_SOFTWARE_ONLY) &&
- (keymaster0_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE)) {
- rc = 1;
- }
-
-out:
- if (keymaster1_dev) {
- keymaster1_close(keymaster1_dev);
- }
- if (keymaster0_dev) {
- keymaster0_close(keymaster0_dev);
- }
- return rc;
-}
-
-/* Create a new keymaster key and store it in this footer */
-static int keymaster_create_key_old(struct crypt_mnt_ftr* ftr) {
- uint8_t* key = 0;
- keymaster0_device_t* keymaster0_dev = 0;
- keymaster1_device_t* keymaster1_dev = 0;
-
- if (ftr->keymaster_blob_size) {
- SLOGI("Already have key");
- return 0;
- }
-
- if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
- SLOGE("Failed to init keymaster");
- return -1;
- }
-
- int rc = 0;
- size_t key_size = 0;
- if (keymaster1_dev) {
- keymaster_key_param_t params[] = {
- /* Algorithm & size specifications. Stick with RSA for now. Switch to AES later. */
- keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
- keymaster_param_int(KM_TAG_KEY_SIZE, RSA_KEY_SIZE),
- keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, RSA_EXPONENT),
-
- /* The only allowed purpose for this key is signing. */
- keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
-
- /* Padding & digest specifications. */
- keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
- keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
-
- /* Require that the key be usable in standalone mode. File system isn't available. */
- keymaster_param_enum(KM_TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE),
-
- /* No auth requirements, because cryptfs is not yet integrated with gatekeeper. */
- keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
-
- /* Rate-limit key usage attempts, to rate-limit brute force */
- keymaster_param_int(KM_TAG_MIN_SECONDS_BETWEEN_OPS, KEYMASTER_CRYPTFS_RATE_LIMIT),
- };
- keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
- keymaster_key_blob_t key_blob;
- keymaster_error_t error = keymaster1_dev->generate_key(
- keymaster1_dev, ¶m_set, &key_blob, NULL /* characteristics */);
- if (error != KM_ERROR_OK) {
- SLOGE("Failed to generate keymaster1 key, error %d", error);
- rc = -1;
- goto out;
- }
-
- key = (uint8_t*)key_blob.key_material;
- key_size = key_blob.key_material_size;
- } else if (keymaster0_dev) {
- keymaster_rsa_keygen_params_t params;
- memset(¶ms, '\0', sizeof(params));
- params.public_exponent = RSA_EXPONENT;
- params.modulus_size = RSA_KEY_SIZE;
-
- if (keymaster0_dev->generate_keypair(keymaster0_dev, TYPE_RSA, ¶ms, &key, &key_size)) {
- SLOGE("Failed to generate keypair");
- rc = -1;
- goto out;
- }
- } else {
- SLOGE("Cryptfs bug: keymaster_init succeeded but didn't initialize a device");
- rc = -1;
- goto out;
- }
-
- if (key_size > KEYMASTER_BLOB_SIZE) {
- SLOGE("Keymaster key too large for crypto footer");
- rc = -1;
- goto out;
- }
-
- memcpy(ftr->keymaster_blob, key, key_size);
- ftr->keymaster_blob_size = key_size;
-
-out:
- if (keymaster0_dev) keymaster0_close(keymaster0_dev);
- if (keymaster1_dev) keymaster1_close(keymaster1_dev);
- free(key);
- return rc;
-}
-
-/* This signs the given object using the keymaster key. */
-static int keymaster_sign_object_old(struct crypt_mnt_ftr* ftr, const unsigned char* object,
- const size_t object_size, unsigned char** signature,
- size_t* signature_size) {
- int rc = 0;
- keymaster0_device_t* keymaster0_dev = 0;
- keymaster1_device_t* keymaster1_dev = 0;
-
- unsigned char to_sign[RSA_KEY_SIZE_BYTES];
- size_t to_sign_size = sizeof(to_sign);
- memset(to_sign, 0, RSA_KEY_SIZE_BYTES);
-
- if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
- SLOGE("Failed to init keymaster");
- rc = -1;
- goto out;
- }
-
- // To sign a message with RSA, the message must satisfy two
- // constraints:
- //
- // 1. The message, when interpreted as a big-endian numeric value, must
- // be strictly less than the public modulus of the RSA key. Note
- // that because the most significant bit of the public modulus is
- // guaranteed to be 1 (else it's an (n-1)-bit key, not an n-bit
- // key), an n-bit message with most significant bit 0 always
- // satisfies this requirement.
- //
- // 2. The message must have the same length in bits as the public
- // modulus of the RSA key. This requirement isn't mathematically
- // necessary, but is necessary to ensure consistency in
- // implementations.
- switch (ftr->kdf_type) {
- case KDF_SCRYPT_KEYMASTER:
- // This ensures the most significant byte of the signed message
- // is zero. We could have zero-padded to the left instead, but
- // this approach is slightly more robust against changes in
- // object size. However, it's still broken (but not unusably
- // so) because we really should be using a proper deterministic
- // RSA padding function, such as PKCS1.
- memcpy(to_sign + 1, object, min(RSA_KEY_SIZE_BYTES - 1, object_size));
- SLOGI("Signing safely-padded object");
- break;
- default:
- SLOGE("Unknown KDF type %d", ftr->kdf_type);
- rc = -1;
- goto out;
- }
-
- if (keymaster0_dev) {
- keymaster_rsa_sign_params_t params;
- params.digest_type = DIGEST_NONE;
- params.padding_type = PADDING_NONE;
-
- rc = keymaster0_dev->sign_data(keymaster0_dev, ¶ms, ftr->keymaster_blob,
- ftr->keymaster_blob_size, to_sign, to_sign_size, signature,
- signature_size);
- goto out;
- } else if (keymaster1_dev) {
- keymaster_key_blob_t key = {ftr->keymaster_blob, ftr->keymaster_blob_size};
- keymaster_key_param_t params[] = {
- keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
- keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
- };
- keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
- keymaster_operation_handle_t op_handle;
- keymaster_error_t error = keymaster1_dev->begin(
- keymaster1_dev, KM_PURPOSE_SIGN, &key, ¶m_set, NULL /* out_params */, &op_handle);
- if (error == KM_ERROR_KEY_RATE_LIMIT_EXCEEDED) {
- // Key usage has been rate-limited. Wait a bit and try again.
- sleep(KEYMASTER_CRYPTFS_RATE_LIMIT);
- error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key, ¶m_set,
- NULL /* out_params */, &op_handle);
- }
- if (error != KM_ERROR_OK) {
- SLOGE("Error starting keymaster signature transaction: %d", error);
- rc = -1;
- goto out;
- }
-
- keymaster_blob_t input = {to_sign, to_sign_size};
- size_t input_consumed;
- error = keymaster1_dev->update(keymaster1_dev, op_handle, NULL /* in_params */, &input,
- &input_consumed, NULL /* out_params */, NULL /* output */);
- if (error != KM_ERROR_OK) {
- SLOGE("Error sending data to keymaster signature transaction: %d", error);
- rc = -1;
- goto out;
- }
- if (input_consumed != to_sign_size) {
- // This should never happen. If it does, it's a bug in the keymaster implementation.
- SLOGE("Keymaster update() did not consume all data.");
- keymaster1_dev->abort(keymaster1_dev, op_handle);
- rc = -1;
- goto out;
- }
-
- keymaster_blob_t tmp_sig;
- error = keymaster1_dev->finish(keymaster1_dev, op_handle, NULL /* in_params */,
- NULL /* verify signature */, NULL /* out_params */, &tmp_sig);
- if (error != KM_ERROR_OK) {
- SLOGE("Error finishing keymaster signature transaction: %d", error);
- rc = -1;
- goto out;
- }
-
- *signature = (uint8_t*)tmp_sig.data;
- *signature_size = tmp_sig.data_length;
- } else {
- SLOGE("Cryptfs bug: keymaster_init succeded but didn't initialize a device.");
- rc = -1;
- goto out;
- }
-
-out:
- if (keymaster1_dev) keymaster1_close(keymaster1_dev);
- if (keymaster0_dev) keymaster0_close(keymaster0_dev);
-
- return rc;
-}
-
-/* Should we use keymaster? */
-static int keymaster_check_compatibility_new() {
- return keymaster_compatibility_cryptfs_scrypt();
-}
-
-#if 0
-/* Create a new keymaster key and store it in this footer */
-static int keymaster_create_key_new(struct crypt_mnt_ftr *ftr)
-{
- if (ftr->keymaster_blob_size) {
- SLOGI("Already have key");
- return 0;
- }
-
- int rc = keymaster_create_key_for_cryptfs_scrypt(RSA_KEY_SIZE, RSA_EXPONENT,
- KEYMASTER_CRYPTFS_RATE_LIMIT, ftr->keymaster_blob, KEYMASTER_BLOB_SIZE,
- &ftr->keymaster_blob_size);
- if (rc) {
- if (ftr->keymaster_blob_size > KEYMASTER_BLOB_SIZE) {
- SLOGE("Keymaster key blob to large)");
- ftr->keymaster_blob_size = 0;
- }
- SLOGE("Failed to generate keypair");
- return -1;
- }
- return 0;
-}
-#endif
-
-/* This signs the given object using the keymaster key. */
-static int keymaster_sign_object_new(struct crypt_mnt_ftr* ftr, const unsigned char* object,
- const size_t object_size, unsigned char** signature,
- size_t* signature_size) {
- unsigned char to_sign[RSA_KEY_SIZE_BYTES];
- size_t to_sign_size = sizeof(to_sign);
- memset(to_sign, 0, RSA_KEY_SIZE_BYTES);
-
- // To sign a message with RSA, the message must satisfy two
- // constraints:
- //
- // 1. The message, when interpreted as a big-endian numeric value, must
- // be strictly less than the public modulus of the RSA key. Note
- // that because the most significant bit of the public modulus is
- // guaranteed to be 1 (else it's an (n-1)-bit key, not an n-bit
- // key), an n-bit message with most significant bit 0 always
- // satisfies this requirement.
- //
- // 2. The message must have the same length in bits as the public
- // modulus of the RSA key. This requirement isn't mathematically
- // necessary, but is necessary to ensure consistency in
- // implementations.
- switch (ftr->kdf_type) {
- case KDF_SCRYPT_KEYMASTER:
- // This ensures the most significant byte of the signed message
- // is zero. We could have zero-padded to the left instead, but
- // this approach is slightly more robust against changes in
- // object size. However, it's still broken (but not unusably
- // so) because we really should be using a proper deterministic
- // RSA padding function, such as PKCS1.
- memcpy(to_sign + 1, object, min(RSA_KEY_SIZE_BYTES - 1, object_size));
- SLOGI("Signing safely-padded object");
- break;
- default:
- SLOGE("Unknown KDF type %d", ftr->kdf_type);
- return -1;
- }
- if (keymaster_sign_object_for_cryptfs_scrypt(
- ftr->keymaster_blob, ftr->keymaster_blob_size, KEYMASTER_CRYPTFS_RATE_LIMIT, to_sign,
- to_sign_size, signature, signature_size) != KeymasterSignResult::ok)
- return -1;
- return 0;
-}
-
-namespace android {
-
-class CryptFsTest : public testing::Test {
- protected:
- virtual void SetUp() {}
-
- virtual void TearDown() {}
-};
-
-TEST_F(CryptFsTest, ScryptHidlizationEquivalenceTest) {
- crypt_mnt_ftr ftr;
- ftr.kdf_type = KDF_SCRYPT_KEYMASTER;
- ftr.keymaster_blob_size = 0;
-
- ASSERT_EQ(0, keymaster_create_key_old(&ftr));
-
- uint8_t* sig1 = nullptr;
- uint8_t* sig2 = nullptr;
- size_t sig_size1 = 123456789;
- size_t sig_size2 = 123456789;
- uint8_t object[] = "the object";
-
- ASSERT_EQ(1, keymaster_check_compatibility_old());
- ASSERT_EQ(1, keymaster_check_compatibility_new());
- ASSERT_EQ(0, keymaster_sign_object_old(&ftr, object, 10, &sig1, &sig_size1));
- ASSERT_EQ(0, keymaster_sign_object_new(&ftr, object, 10, &sig2, &sig_size2));
-
- ASSERT_EQ(sig_size1, sig_size2);
- ASSERT_NE(nullptr, sig1);
- ASSERT_NE(nullptr, sig2);
- EXPECT_EQ(0, memcmp(sig1, sig2, sig_size1));
- free(sig1);
- free(sig2);
-}
-
-} // namespace android
diff --git a/vdc.cpp b/vdc.cpp
index c1b7781..a6a3fb0 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -101,6 +101,8 @@
checkStatus(args, vold->mountDefaultEncrypted());
} else if (args[0] == "volume" && args[1] == "shutdown") {
checkStatus(args, vold->shutdown());
+ } else if (args[0] == "volume" && args[1] == "reset") {
+ checkStatus(args, vold->reset());
} else if (args[0] == "cryptfs" && args[1] == "checkEncryption" && args.size() == 3) {
checkStatus(args, vold->checkEncryption(args[2]));
} else if (args[0] == "cryptfs" && args[1] == "mountFstab" && args.size() == 4) {
@@ -111,7 +113,8 @@
bool supported = false;
checkStatus(args, vold->supportsCheckpoint(&supported));
return supported ? 1 : 0;
- } else if (args[0] == "checkpoint" && args[1] == "supportsBlockCheckpoint" && args.size() == 2) {
+ } else if (args[0] == "checkpoint" && args[1] == "supportsBlockCheckpoint" &&
+ args.size() == 2) {
bool supported = false;
checkStatus(args, vold->supportsBlockCheckpoint(&supported));
return supported ? 1 : 0;
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index a620edd..3a58b2e 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -120,6 +120,31 @@
}
}
+static bool prepare_apex_subdirs(struct selabel_handle* sehandle, const std::string& path) {
+ if (!prepare_dir(sehandle, 0700, 0, 0, path + "/apexdata")) return false;
+
+ auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/apex"), closedir);
+ if (!dirp) {
+ PLOG(ERROR) << "Unable to open apex directory";
+ return false;
+ }
+ 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, '@') != NULL) continue;
+
+ if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, path + "/apexdata/" + name)) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
struct selabel_handle* sehandle = selinux_android_file_context_handle();
@@ -129,6 +154,9 @@
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/storaged")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/rollback")) return false;
+ // TODO: Return false if this returns false once sure this should succeed.
+ prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/apexrollback");
+ prepare_apex_subdirs(sehandle, misc_de_path);
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) {
@@ -144,6 +172,9 @@
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/storaged")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/rollback")) return false;
+ // TODO: Return false if this returns false once sure this should succeed.
+ prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/apexrollback");
+ prepare_apex_subdirs(sehandle, misc_ce_path);
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, system_ce_path + "/backup")) {