Commits

Anonymous committed ba6ae8d

Add support for more expressive SD card permissions

We now run an sdcard fuse daemon on top of a physical SD card.
Add support for that.

Bug: 10330128

Change-Id: I6a291f861ccb0f2911c07cc8f659e2cec4e6d76c

  • Participants
  • Parent commits 71ebe15

Comments (0)

Files changed (7)

 
 // #define PARTITION_DEBUG
 
-DirectVolume::DirectVolume(VolumeManager *vm, const char *label,
-                           const char *mount_point, int partIdx) :
-              Volume(vm, label, mount_point) {
-    mPartIdx = partIdx;
-
+DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) :
+        Volume(vm, rec, flags) {
     mPaths = new PathCollection();
     for (int i = 0; i < MAX_PARTITIONS; i++)
         mPartMinors[i] = -1;
     mDiskMinor = -1;
     mDiskNumParts = 0;
 
+    if (strcmp(rec->mount_point, "auto") != 0) {
+        ALOGE("Vold managed volumes must have auto mount point; ignoring %s",
+              rec->mount_point);
+    }
+
+    char mount[PATH_MAX];
+
+    snprintf(mount, PATH_MAX, "%s/%s", Volume::MEDIA_DIR, rec->label);
+    mMountpoint = strdup(mount);
+    snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label);
+    mFuseMountpoint = strdup(mount);
+
     setState(Volume::State_NoMedia);
 }
 
     return 0;
 }
 
-void DirectVolume::setFlags(int flags) {
-    mFlags = flags;
-}
-
 dev_t DirectVolume::getDiskDevice() {
     return MKDEV(mDiskMajor, mDiskMinor);
 }
 
                     snprintf(msg, sizeof(msg),
                              "Volume %s %s disk inserted (%d:%d)", getLabel(),
-                             getMountpoint(), mDiskMajor, mDiskMinor);
+                             getFuseMountpoint(), mDiskMajor, mDiskMinor);
                     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
                                                          msg, false);
                 }
 
     SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor);
     snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)",
-             getLabel(), getMountpoint(), major, minor);
+             getLabel(), getFuseMountpoint(), major, minor);
     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved,
                                              msg, false);
     setState(Volume::State_NoMedia);
          */
 
         snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)",
-                 getLabel(), getMountpoint(), major, minor);
+                 getLabel(), getFuseMountpoint(), major, minor);
         mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval,
                                              msg, false);
 
 {
     strcpy(v->label, mLabel);
     strcpy(v->mnt_point, mMountpoint);
-    v->flags=mFlags;
+    v->flags = getFlags();
     /* Other fields of struct volume_info are filled in by the caller or cryptfs.c */
 
     return 0;
 public:
     static const int MAX_PARTITIONS = 32;
 protected:
+    const char* mMountpoint;
+    const char* mFuseMountpoint;
+
     PathCollection *mPaths;
     int            mDiskMajor;
     int            mDiskMinor;
     int            mFlags;
 
 public:
-    DirectVolume(VolumeManager *vm, const char *label, const char *mount_point, int partIdx);
+    DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags);
     virtual ~DirectVolume();
 
     int addPath(const char *path);
 
+    const char *getMountpoint() { return mMountpoint; }
+    const char *getFuseMountpoint() { return mFuseMountpoint; }
+
     int handleBlockEvent(NetlinkEvent *evt);
     dev_t getDiskDevice();
     dev_t getShareDevice();
     void handleVolumeShared();
     void handleVolumeUnshared();
     int getVolInfo(struct volume_info *v);
-    void setFlags(int flags);
 
 protected:
     int getDeviceNodes(dev_t *devs, int max);
 
 #define LOG_TAG "Vold"
 
+#include <cutils/fs.h>
 #include <cutils/log.h>
 
 #include "Volume.h"
 
 
 /*
- * Secure directory - stuff that only root can see
+ * Media directory - stuff that only media_rw user can see
  */
-const char *Volume::SECDIR            = "/mnt/secure";
+const char *Volume::MEDIA_DIR           = "/mnt/media_rw";
 
 /*
- * Secure staging directory - where media is mounted for preparation
+ * Fuse directory - location where fuse wrapped filesystems go
  */
-const char *Volume::SEC_STGDIR        = "/mnt/secure/staging";
-
-/*
- * Path to the directory on the media which contains publicly accessable
- * asec imagefiles. This path will be obscured before the mount is
- * exposed to non priviledged users.
- */
-const char *Volume::SEC_STG_SECIMGDIR = "/mnt/secure/staging/.android_secure";
+const char *Volume::FUSE_DIR           = "/storage";
 
 /*
  * Path to external storage where *only* root can access ASEC image files
         return "Unknown-Error";
 }
 
-Volume::Volume(VolumeManager *vm, const char *label, const char *mount_point) {
+Volume::Volume(VolumeManager *vm, const fstab_rec* rec, int flags) {
     mVm = vm;
     mDebug = false;
-    mLabel = strdup(label);
-    mMountpoint = strdup(mount_point);
+    mLabel = strdup(rec->label);
     mState = Volume::State_Init;
+    mFlags = flags;
     mCurrentlyMountedKdev = -1;
-    mPartIdx = -1;
+    mPartIdx = rec->partnum;
     mRetryMount = false;
 }
 
 Volume::~Volume() {
     free(mLabel);
-    free(mMountpoint);
 }
 
 void Volume::protectFromAutorunStupidity() {
     char filename[255];
 
-    snprintf(filename, sizeof(filename), "%s/autorun.inf", SEC_STGDIR);
+    snprintf(filename, sizeof(filename), "%s/autorun.inf", getMountpoint());
     if (!access(filename, F_OK)) {
         SLOGW("Volume contains an autorun.inf! - removing");
         /*
          oldState, stateToStr(oldState), mState, stateToStr(mState));
     snprintf(msg, sizeof(msg),
              "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
-             getMountpoint(), oldState, stateToStr(oldState), mState,
+             getFuseMountpoint(), oldState, stateToStr(oldState), mState,
              stateToStr(mState));
 
     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
     dev_t deviceNodes[4];
     int n, i, rc = 0;
     char errmsg[255];
-    const char* externalStorage = getenv("EXTERNAL_STORAGE");
-    bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage);
+
+    int flags = getFlags();
+    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;
+
+    // TODO: handle "bind" style mounts, for emulated storage
+
     char decrypt_state[PROPERTY_VALUE_MAX];
     char crypto_state[PROPERTY_VALUE_MAX];
     char encrypt_progress[PROPERTY_VALUE_MAX];
-    int flags;
 
     property_get("vold.decrypt", decrypt_state, "");
     property_get("vold.encrypt_progress", encrypt_progress, "");
      * or are in the process of encrypting.
      */
     if ((getState() == Volume::State_NoMedia) ||
-        ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && primaryStorage)) {
+        ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) {
         snprintf(errmsg, sizeof(errmsg),
                  "Volume %s %s mount failed - no media",
-                 getLabel(), getMountpoint());
+                 getLabel(), getFuseMountpoint());
         mVm->getBroadcaster()->sendBroadcast(
                                          ResponseCode::VolumeMountFailedNoMedia,
                                          errmsg, false);
     }
 
     /* If we're running encrypted, and the volume is marked as encryptable and nonremovable,
-     * and vold is asking to mount the primaryStorage device, then we need to decrypt
+     * and also marked as providing Asec storage, then we need to decrypt
      * that partition, and update the volume object to point to it's new decrypted
      * block device
      */
     property_get("ro.crypto.state", crypto_state, "");
-    flags = getFlags();
-    if (primaryStorage &&
+    if (providesAsec &&
         ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) &&
         !strcmp(crypto_state, "encrypted") && !isDecrypted()) {
        char new_sys_path[MAXPATHLEN];
             return -1;
         }
 
-        /*
-         * Mount the device on our internal staging mountpoint so we can
-         * muck with it before exposing it to non priviledged users.
-         */
         errno = 0;
         int gid;
 
-        if (primaryStorage) {
-            // Special case the primary SD card.
-            // For this we grant write access to the SDCARD_RW group.
-            gid = AID_SDCARD_RW;
-        } else {
-            // For secondary external storage we keep things locked up.
-            gid = AID_MEDIA_RW;
-        }
-        if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,
-                AID_SYSTEM, gid, 0702, true)) {
+        if (Fat::doMount(devicePath, getMountpoint(), false, false, false,
+                AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
             SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
             continue;
         }
 
-        SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
-
         protectFromAutorunStupidity();
 
-        // only create android_secure on primary storage
-        if (primaryStorage && createBindMounts()) {
-            SLOGE("Failed to create bindmounts (%s)", strerror(errno));
-            umount("/mnt/secure/staging");
+        if (providesAsec && mountAsecExternal() != 0) {
+            SLOGE("Failed to mount secure area (%s)", strerror(errno));
+            umount(getMountpoint());
             setState(Volume::State_Idle);
             return -1;
         }
 
-        /*
-         * Now that the bindmount trickery is done, atomically move the
-         * whole subtree to expose it to non priviledged users.
-         */
-        if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
-            SLOGE("Failed to move mount (%s)", strerror(errno));
-            umount("/mnt/secure/staging");
-            setState(Volume::State_Idle);
-            return -1;
-        }
+        char service[64];
+        snprintf(service, 64, "fuse_%s", getLabel());
+        property_set("ctl.start", service);
+
         setState(Volume::State_Mounted);
         mCurrentlyMountedKdev = deviceNodes[i];
         return 0;
     return -1;
 }
 
-int Volume::createBindMounts() {
-    unsigned long flags;
+int Volume::mountAsecExternal() {
+    char legacy_path[PATH_MAX];
+    char secure_path[PATH_MAX];
 
-    /*
-     * Rename old /android_secure -> /.android_secure
-     */
-    if (!access("/mnt/secure/staging/android_secure", R_OK | X_OK) &&
-         access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
-        if (rename("/mnt/secure/staging/android_secure", SEC_STG_SECIMGDIR)) {
-            SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno));
-        }
-    }
-
-    /*
-     * Ensure that /android_secure exists and is a directory
-     */
-    if (access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
-        if (errno == ENOENT) {
-            if (mkdir(SEC_STG_SECIMGDIR, 0777)) {
-                SLOGE("Failed to create %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
-                return -1;
-            }
-        } else {
-            SLOGE("Failed to access %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
-            return -1;
-        }
-    } else {
-        struct stat sbuf;
+    snprintf(legacy_path, PATH_MAX, "%s/android_secure", getMountpoint());
+    snprintf(secure_path, PATH_MAX, "%s/.android_secure", getMountpoint());
 
-        if (stat(SEC_STG_SECIMGDIR, &sbuf)) {
-            SLOGE("Failed to stat %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
-            return -1;
-        }
-        if (!S_ISDIR(sbuf.st_mode)) {
-            SLOGE("%s is not a directory", SEC_STG_SECIMGDIR);
-            errno = ENOTDIR;
-            return -1;
+    // Recover legacy secure path
+    if (!access(legacy_path, R_OK | X_OK) && access(secure_path, R_OK | X_OK)) {
+        if (rename(legacy_path, secure_path)) {
+            SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno));
         }
     }
 
-    /*
-     * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
-     * have a root only accessable mountpoint for it.
-     */
-    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
-        SLOGE("Failed to bind mount points %s -> %s (%s)",
-                SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, strerror(errno));
+    if (fs_prepare_dir(secure_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
         return -1;
     }
 
-    /*
-     * Mount a read-only, zero-sized tmpfs  on <mountpoint>/android_secure to
-     * obscure the underlying directory from everybody - sneaky eh? ;)
-     */
-    if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=000,uid=0,gid=0")) {
-        SLOGE("Failed to obscure %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
-        umount("/mnt/asec_secure");
+    if (mount(secure_path, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
+        SLOGE("Failed to bind mount points %s -> %s (%s)", secure_path,
+                SEC_ASECDIR_EXT, strerror(errno));
         return -1;
     }
 
     return 0;
 }
 
-int Volume::doMoveMount(const char *src, const char *dst, bool force) {
-    unsigned int flags = MS_MOVE;
-    int retries = 5;
-
-    while(retries--) {
-        if (!mount(src, dst, "", flags, NULL)) {
-            if (mDebug) {
-                SLOGD("Moved mount %s -> %s sucessfully", src, dst);
-            }
-            return 0;
-        } else if (errno != EBUSY) {
-            SLOGE("Failed to move mount %s -> %s (%s)", src, dst, strerror(errno));
-            return -1;
-        }
-        int action = 0;
-
-        if (force) {
-            if (retries == 1) {
-                action = 2; // SIGKILL
-            } else if (retries == 2) {
-                action = 1; // SIGHUP
-            }
-        }
-        SLOGW("Failed to move %s -> %s (%s, retries %d, action %d)",
-                src, dst, strerror(errno), retries, action);
-        Process::killProcessesWithOpenFiles(src, action);
-        usleep(1000*250);
-    }
-
-    errno = EBUSY;
-    SLOGE("Giving up on move %s -> %s (%s)", src, dst, strerror(errno));
-    return -1;
-}
-
 int Volume::doUnmount(const char *path, bool force) {
     int retries = 10;
 
 int Volume::unmountVol(bool force, bool revert) {
     int i, rc;
 
+    int flags = getFlags();
+    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;
+
     if (getState() != Volume::State_Mounted) {
         SLOGE("Volume %s unmount request when not mounted", getLabel());
         errno = EINVAL;
     setState(Volume::State_Unmounting);
     usleep(1000 * 1000); // Give the framework some time to react
 
-    /*
-     * Remove the bindmount we were using to keep a reference to
-     * the previously obscured directory.
-     */
-    if (doUnmount(Volume::SEC_ASECDIR_EXT, force)) {
-        SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR_EXT, strerror(errno));
-        goto fail_remount_tmpfs;
+    char service[64];
+    snprintf(service, 64, "fuse_%s", getLabel());
+    property_set("ctl.stop", service);
+    /* Give it a chance to stop.  I wish we had a synchronous way to determine this... */
+    sleep(1);
+
+    // TODO: determine failure mode if FUSE times out
+
+    if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) {
+        SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno));
+        goto out_mounted;
     }
 
-    /*
-     * Unmount the tmpfs which was obscuring the asec image directory
-     * from non root users
-     */
-    char secure_dir[PATH_MAX];
-    snprintf(secure_dir, PATH_MAX, "%s/.android_secure", getMountpoint());
-    if (doUnmount(secure_dir, force)) {
-        SLOGE("Failed to unmount tmpfs on %s (%s)", secure_dir, strerror(errno));
-        goto fail_republish;
+    /* Now that the fuse daemon is dead, unmount it */
+    if (doUnmount(getFuseMountpoint(), force) != 0) {
+        SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno));
+        goto fail_remount_secure;
     }
 
-    /*
-     * Finally, unmount the actual block device from the staging dir
-     */
-    if (doUnmount(getMountpoint(), force)) {
-        SLOGE("Failed to unmount %s (%s)", SEC_STGDIR, strerror(errno));
-        goto fail_recreate_bindmount;
+    /* Unmount the real sd card */
+    if (doUnmount(getMountpoint(), force) != 0) {
+        SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno));
+        goto fail_remount_secure;
     }
 
-    SLOGI("%s unmounted sucessfully", getMountpoint());
+    SLOGI("%s unmounted successfully", getMountpoint());
 
     /* If this is an encrypted volume, and we've been asked to undo
      * the crypto mapping, then revert the dm-crypt mapping, and revert
     mCurrentlyMountedKdev = -1;
     return 0;
 
-    /*
-     * Failure handling - try to restore everything back the way it was
-     */
-fail_recreate_bindmount:
-    if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
-        SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!");
-        goto out_nomedia;
-    }
-fail_remount_tmpfs:
-    if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=0,uid=0,gid=0")) {
-        SLOGE("Failed to restore tmpfs after failure! - Storage will appear offline!");
-        goto out_nomedia;
-    }
-fail_republish:
-    if (doMoveMount(SEC_STGDIR, getMountpoint(), force)) {
-        SLOGE("Failed to republish mount after failure! - Storage will appear offline!");
+fail_remount_secure:
+    if (providesAsec && mountAsecExternal() != 0) {
+        SLOGE("Failed to remount secure area (%s)", strerror(errno));
         goto out_nomedia;
     }
 
+out_mounted:
     setState(Volume::State_Mounted);
     return -1;
 
     setState(Volume::State_NoMedia);
     return -1;
 }
+
 int Volume::initializeMbr(const char *deviceNode) {
     struct disk_info dinfo;
 
 #define _VOLUME_H
 
 #include <utils/List.h>
+#include <fs_mgr.h>
 
 class NetlinkEvent;
 class VolumeManager;
 class Volume {
 private:
     int mState;
+    int mFlags;
 
 public:
     static const int State_Init       = -1;
     static const int State_Shared     = 7;
     static const int State_SharedMnt  = 8;
 
-    static const char *SECDIR;
-    static const char *SEC_STGDIR;
-    static const char *SEC_STG_SECIMGDIR;
+    static const char *MEDIA_DIR;
+    static const char *FUSE_DIR;
     static const char *SEC_ASECDIR_EXT;
     static const char *SEC_ASECDIR_INT;
     static const char *ASECDIR;
 
 protected:
     char *mLabel;
-    char *mMountpoint;
     VolumeManager *mVm;
     bool mDebug;
     int mPartIdx;
     dev_t mCurrentlyMountedKdev;
 
 public:
-    Volume(VolumeManager *vm, const char *label, const char *mount_point);
+    Volume(VolumeManager *vm, const fstab_rec* rec, int flags);
     virtual ~Volume();
 
     int mountVol();
     int formatVol(bool wipe);
 
     const char *getLabel() { return mLabel; }
-    const char *getMountpoint() { return mMountpoint; }
     int getState() { return mState; }
+    int getFlags() { return mFlags; };
+
+    /* Mountpoint of the raw volume */
+    virtual const char *getMountpoint() = 0;
+    virtual const char *getFuseMountpoint() = 0;
 
     virtual int handleBlockEvent(NetlinkEvent *evt);
     virtual dev_t getDiskDevice();
     virtual int updateDeviceInfo(char *new_path, int new_major, int new_minor) = 0;
     virtual void revertDeviceInfo(void) = 0;
     virtual int isDecrypted(void) = 0;
-    virtual int getFlags(void) = 0;
 
     int createDeviceNode(const char *path, int major, int minor);
 
 private:
     int initializeMbr(const char *deviceNode);
     bool isMountpointMounted(const char *path);
-    int createBindMounts();
+    int mountAsecExternal();
     int doUnmount(const char *path, bool force);
-    int doMoveMount(const char *src, const char *dst, bool force);
     void protectFromAutorunStupidity();
 };
 

VolumeManager.cpp

     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
         char *buffer;
         asprintf(&buffer, "%s %s %d",
-                 (*i)->getLabel(), (*i)->getMountpoint(),
+                 (*i)->getLabel(), (*i)->getFuseMountpoint(),
                  (*i)->getState());
         cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
         free(buffer);
     VolumeCollection::iterator i;
 
     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
-        const char* mountPoint = (*i)->getMountpoint();
+        const char* mountPoint = (*i)->getFuseMountpoint();
         if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
             return *i;
         }
 
     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
         if (label[0] == '/') {
-            if (!strcmp(label, (*i)->getMountpoint()))
+            if (!strcmp(label, (*i)->getFuseMountpoint()))
                 return (*i);
         } else {
             if (!strcmp(label, (*i)->getLabel()))
 
     for (AsecIdCollection::iterator it = toUnmount.begin(); it != toUnmount.end(); ++it) {
         ContainerData *cd = *it;
-        SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
+        SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getFuseMountpoint());
         if (unmountObb(cd->id, force)) {
             SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
             rc = -1;
    char crypto_blkdev[256];
    char label[256];
 };
-#define VOL_NONREMOVABLE 0x1
-#define VOL_ENCRYPTABLE  0x2
+#define VOL_NONREMOVABLE   0x1
+#define VOL_ENCRYPTABLE    0x2
+#define VOL_PRIMARY        0x4
+#define VOL_PROVIDES_ASEC  0x8
 
 #ifdef __cplusplus
 extern "C" {
             DirectVolume *dv = NULL;
             flags = 0;
 
-            dv = new DirectVolume(vm, fstab->recs[i].label,
-                                  fstab->recs[i].mount_point,
-                                  fstab->recs[i].partnum);
-
-            if (dv->addPath(fstab->recs[i].blk_device)) {
-                SLOGE("Failed to add devpath %s to volume %s",
-                      fstab->recs[i].blk_device, fstab->recs[i].label);
-                goto out_fail;
-            }
-
             /* Set any flags that might be set for this volume */
             if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
                 flags |= VOL_NONREMOVABLE;
             if (fs_mgr_is_encryptable(&fstab->recs[i])) {
                 flags |= VOL_ENCRYPTABLE;
             }
-            dv->setFlags(flags);
+            /* Only set this flag if there is not an emulated sd card */
+            if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) &&
+                !strcmp(fstab->recs[i].fs_type, "vfat")) {
+                flags |= VOL_PROVIDES_ASEC;
+            }
+            dv = new DirectVolume(vm, &(fstab->recs[i]), flags);
+
+            if (dv->addPath(fstab->recs[i].blk_device)) {
+                SLOGE("Failed to add devpath %s to volume %s",
+                      fstab->recs[i].blk_device, fstab->recs[i].label);
+                goto out_fail;
+            }
 
             vm->addVolume(dv);
         }