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;