Merge "Remove libfscrypt now it's in libfs_mgr" am: 43f8298bdd am: ce187e7fd6
am: ff5ad94627
Change-Id: Ibeaec1d3fd09893706cd927ff715f5f76d516749
diff --git a/Android.bp b/Android.bp
index 452746c..323bc3c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -228,6 +228,7 @@
"libhardware_legacy",
"libhidlbase",
"libkeymaster4support",
+ "libutils",
],
}
diff --git a/Keymaster.h b/Keymaster.h
index 42a2b5d..9a0616d 100644
--- a/Keymaster.h
+++ b/Keymaster.h
@@ -115,7 +115,7 @@
bool isSecure();
private:
- std::unique_ptr<KmDevice> mDevice;
+ sp<KmDevice> mDevice;
DISALLOW_COPY_AND_ASSIGN(Keymaster);
static bool hmacKeyGenerated;
};
diff --git a/Utils.cpp b/Utils.cpp
index 1616d80..e5bf33d 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -165,7 +165,7 @@
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
-
+ PLOG(INFO) << "ForceUnmount failed";
return -errno;
}
@@ -985,5 +985,52 @@
return true;
}
+int MountUserFuse(userid_t user_id, const std::string& relative_path,
+ android::base::unique_fd* fuse_fd) {
+ std::string path(StringPrintf("/mnt/user/%d/%s", user_id, relative_path.c_str()));
+
+ // Force remove the existing mount before we attempt to prepare the
+ // directory. If we have a dangling mount, then PrepareDir may fail if the
+ // indirection to FUSE doesn't work.
+ android::status_t result = android::vold::ForceUnmount(path);
+ if (result != android::OK) {
+ PLOG(ERROR) << "Failed to unmount " << path;
+ return -1;
+ }
+
+ // Create directories.
+ result = android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT);
+ if (result != android::OK) {
+ PLOG(ERROR) << "Failed to prepare directory " << path;
+ return -1;
+ }
+
+ // Open fuse fd.
+ fuse_fd->reset(open("/dev/fuse", O_RDWR | O_CLOEXEC));
+ if (fuse_fd->get() == -1) {
+ PLOG(ERROR) << "Failed to open /dev/fuse";
+ return -1;
+ }
+
+ // Note: leaving out default_permissions since we don't want kernel to do lower filesystem
+ // permission checks before routing to FUSE daemon.
+ const auto opts = StringPrintf(
+ "fd=%i,"
+ "rootmode=40000,"
+ "allow_other,"
+ "user_id=0,group_id=0,",
+ fuse_fd->get());
+
+ const int result_int =
+ TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse",
+ MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME,
+ opts.c_str()));
+ if (result_int != 0) {
+ PLOG(ERROR) << "Failed to mount " << path;
+ return -errno;
+ }
+ return 0;
+}
+
} // namespace vold
} // namespace android
diff --git a/Utils.h b/Utils.h
index af4e401..f607c81 100644
--- a/Utils.h
+++ b/Utils.h
@@ -20,6 +20,7 @@
#include "KeyBuffer.h"
#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
#include <cutils/multiuser.h>
#include <selinux/selinux.h>
#include <utils/Errors.h>
@@ -33,6 +34,8 @@
namespace android {
namespace vold {
+static const char* kPropFuseSnapshot = "sys.fuse_snapshot";
+
/* SELinux contexts used depending on the block device type */
extern security_context_t sBlkidContext;
extern security_context_t sBlkidUntrustedContext;
@@ -147,6 +150,10 @@
bool FsyncDirectory(const std::string& dirname);
bool writeStringToFile(const std::string& payload, const std::string& filename);
+
+int MountUserFuse(userid_t user_id, const std::string& relative_path,
+ android::base::unique_fd* fuse_fd);
+
} // namespace vold
} // namespace android
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index f17f59f..20e1290 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -326,7 +326,8 @@
}
binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
- int32_t mountUserId) {
+ int32_t mountUserId,
+ android::base::unique_fd* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT;
CHECK_ARGUMENT_ID(volId);
ACQUIRE_LOCK;
@@ -343,6 +344,14 @@
if (res != OK) {
return translate(res);
}
+
+ _aidl_return->reset(dup(vol->getFuseFd().get()));
+ if (_aidl_return->get() == -1) {
+ // Let's not return invalid fd since binder will not allow null fds. Instead give it a
+ // default value.
+ _aidl_return->reset(open("/dev/null", O_RDONLY | O_CLOEXEC));
+ }
+
if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
res = VolumeManager::Instance()->setPrimary(vol);
if (res != OK) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 13137c5..744ff84 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -52,7 +52,8 @@
binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid);
- binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId);
+ binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId,
+ android::base::unique_fd* _aidl_return);
binder::Status unmount(const std::string& volId);
binder::Status format(const std::string& volId, const std::string& fsType);
binder::Status benchmark(const std::string& volId,
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 44bff5a..b0e0b23 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -31,6 +31,7 @@
#include <sys/wait.h>
#include <unistd.h>
#include <array>
+#include <thread>
#include <linux/kdev_t.h>
@@ -100,6 +101,22 @@
VolumeManager* VolumeManager::sInstance = NULL;
+static void* symlinkPrimary(void* data) {
+ std::unique_ptr<std::pair<std::string, std::string>> linkInfo(
+ static_cast<std::pair<std::string, std::string>*>(data));
+ std::string* source = &linkInfo->first;
+ std::string* target = &linkInfo->second;
+
+ fs_prepare_dir(source->c_str(), 0755, AID_ROOT, AID_ROOT);
+ fs_prepare_dir(target->c_str(), 0755, AID_ROOT, AID_ROOT);
+ *target = *target + "/primary";
+
+ // Link source to target
+ LOG(DEBUG) << "Linking " << *source << " to " << *target;
+ Symlink(*source, *target);
+ return nullptr;
+}
+
VolumeManager* VolumeManager::Instance() {
if (!sInstance) sInstance = new VolumeManager();
return sInstance;
@@ -365,6 +382,22 @@
}
int VolumeManager::linkPrimary(userid_t userId) {
+ bool isFuse = GetBoolProperty(android::vold::kPropFuseSnapshot, false);
+
+ if (isFuse) {
+ // Here we have to touch /mnt/user/userid>/<volumeid> which was already mounted as part of
+ // the boot sequence, requiring waiting till a fuse handler is available. If we do this work
+ // in foreground we could hang the caller, i.e. system server, which needs to start the fuse
+ // handler. So do it in the background.
+ std::string source(
+ StringPrintf("/mnt/user/%d/%s/%d", userId, mPrimary->getId().c_str(), userId));
+ std::string target(StringPrintf("/mnt/user/%d/self", userId));
+
+ auto symlinkInfo = new std::pair<std::string, std::string>(source, target);
+ std::thread(symlinkPrimary, symlinkInfo).detach();
+ return 0;
+ }
+
std::string source(mPrimary->getPath());
if (mPrimary->isEmulated()) {
source = StringPrintf("%s/%d", source.c_str(), userId);
@@ -431,6 +464,10 @@
}
int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
+ if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) {
+ // TODO(135341433): Implement fuse specific logic.
+ return 0;
+ }
std::string mode;
switch (mountMode) {
case VoldNativeService::REMOUNT_MODE_NONE:
@@ -450,6 +487,9 @@
case VoldNativeService::REMOUNT_MODE_FULL:
mode = "full";
break;
+ case VoldNativeService::REMOUNT_MODE_PASS_THROUGH:
+ mode = "pass_through";
+ break;
default:
PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode);
return -1;
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 8e5c53d..91c0172 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -40,7 +40,7 @@
void partition(@utf8InCpp String diskId, int partitionType, int ratio);
void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid);
- void mount(@utf8InCpp String volId, int mountFlags, int mountUserId);
+ FileDescriptor mount(@utf8InCpp String volId, int mountFlags, int mountUserId);
void unmount(@utf8InCpp String volId);
void format(@utf8InCpp String volId, @utf8InCpp String fsType);
void benchmark(@utf8InCpp String volId, IVoldTaskListener listener);
@@ -158,6 +158,7 @@
const int REMOUNT_MODE_LEGACY = 4;
const int REMOUNT_MODE_INSTALLER = 5;
const int REMOUNT_MODE_FULL = 6;
+ const int REMOUNT_MODE_PASS_THROUGH = 7;
const int VOLUME_STATE_UNMOUNTED = 0;
const int VOLUME_STATE_CHECKING = 1;
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 552fe2f..c84fbb7 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -15,10 +15,13 @@
*/
#include "EmulatedVolume.h"
+
+#include "AppFuseUtil.h"
#include "Utils.h"
#include "VolumeManager.h"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
@@ -81,7 +84,27 @@
dev_t before = GetDevice(mFuseFull);
+ bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
+
+ if (isFuse) {
+ LOG(INFO) << "Mounting emulated fuse volume";
+ android::base::unique_fd fd;
+ int user_id = getMountUserId();
+ int result = MountUserFuse(user_id, label, &fd);
+
+ if (result != 0) {
+ PLOG(ERROR) << "Failed to mount emulated fuse volume";
+ return -result;
+ }
+ setFuseFd(std::move(fd));
+
+ std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s",
+ user_id, label.c_str()));
+ return BindMount(getInternalPath(), pass_through_path);
+ }
+
if (!(mFusePid = fork())) {
+ LOG(INFO) << "Executing sdcardfs";
// clang-format off
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
@@ -131,6 +154,31 @@
// ENOTCONN until the unmount completes. This is an exotic and unusual
// error code and might cause broken behaviour in applications.
KillProcessesUsingPath(getPath());
+
+ bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
+ if (isFuse) {
+ // We could have migrated storage to an adopted private volume, so always
+ // call primary storage "emulated" to avoid media rescans.
+ std::string label = mLabel;
+ if (getMountFlags() & MountFlags::kPrimary) {
+ label = "emulated";
+ }
+ std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str()));
+ status_t result = ForceUnmount(path);
+ if (result != OK) {
+ // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY.
+ // Figure out why we get EBUSY and remove this special casing if possible.
+ if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL ||
+ errno == ENOENT) {
+ PLOG(INFO) << "ForceUnmount failed on emulated fuse volume";
+ }
+ }
+
+ rmdir(path.c_str());
+ setFuseFd(android::base::unique_fd());
+ return OK;
+ }
+
ForceUnmount(mFuseDefault);
ForceUnmount(mFuseRead);
ForceUnmount(mFuseWrite);
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 0a6b351..7b8a21f 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -15,6 +15,8 @@
*/
#include "PublicVolume.h"
+
+#include "AppFuseUtil.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "fs/Exfat.h"
@@ -167,6 +169,25 @@
dev_t before = GetDevice(mFuseFull);
+ bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
+
+ if (isFuse) {
+ LOG(INFO) << "Mounting public fuse volume";
+ android::base::unique_fd fd;
+ int user_id = getMountUserId();
+ int result = MountUserFuse(user_id, stableName, &fd);
+
+ if (result != 0) {
+ LOG(ERROR) << "Failed to mount public fuse volume";
+ return -result;
+ }
+ setFuseFd(std::move(fd));
+
+ std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s",
+ user_id, stableName.c_str()));
+ return BindMount(getInternalPath(), pass_through_path);
+ }
+
if (!(mFusePid = fork())) {
if (getMountFlags() & MountFlags::kPrimary) {
// clang-format off
@@ -229,6 +250,30 @@
// error code and might cause broken behaviour in applications.
KillProcessesUsingPath(getPath());
+ bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
+ if (isFuse) {
+ // Use UUID as stable name, if available
+ std::string stableName = getId();
+ if (!mFsUuid.empty()) {
+ stableName = mFsUuid;
+ }
+
+ std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str()));
+ status_t result = ForceUnmount(path);
+ if (result != OK) {
+ // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY.
+ // Figure out why we get EBUSY and remove this special casing if possible.
+ if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL ||
+ errno == ENOENT) {
+ PLOG(INFO) << "ForceUnmount failed on public fuse volume";
+ }
+ }
+
+ rmdir(path.c_str());
+ setFuseFd(android::base::unique_fd());
+ return OK;
+ }
+
ForceUnmount(kAsecPath);
ForceUnmount(mFuseDefault);
diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp
index ffc7900..08da8f6 100644
--- a/model/VolumeBase.cpp
+++ b/model/VolumeBase.cpp
@@ -143,6 +143,16 @@
return OK;
}
+status_t VolumeBase::setFuseFd(android::base::unique_fd fuseFd) {
+ if ((mState != State::kChecking) && (mState != State::kEjecting)) {
+ LOG(WARNING) << getId() << " fuse fd change requires state checking or ejecting";
+ return -EBUSY;
+ }
+
+ mFuseFd = std::move(fuseFd);
+ return OK;
+}
+
android::sp<android::os::IVoldListener> VolumeBase::getListener() const {
if (mSilent) {
return nullptr;
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index 53eeb6f..5deecdb 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -87,6 +87,7 @@
State getState() const { return mState; }
const std::string& getPath() const { return mPath; }
const std::string& getInternalPath() const { return mInternalPath; }
+ const android::base::unique_fd& getFuseFd() const { return mFuseFd; }
status_t setDiskId(const std::string& diskId);
status_t setPartGuid(const std::string& partGuid);
@@ -121,6 +122,8 @@
status_t setId(const std::string& id);
status_t setPath(const std::string& path);
status_t setInternalPath(const std::string& internalPath);
+ // Takes ownership of the fd passed in.
+ status_t setFuseFd(android::base::unique_fd fuseFd);
android::sp<android::os::IVoldListener> getListener() const;
@@ -147,6 +150,8 @@
std::string mInternalPath;
/* Flag indicating that volume should emit no events */
bool mSilent;
+ /* The filedescriptor for the fuse device, if the volume uses fuse, or -1 otherwise */
+ android::base::unique_fd mFuseFd;
/* Volumes stacked on top of this volume */
std::list<std::shared_ptr<VolumeBase>> mVolumes;