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
This commit is contained in:
Jeff Sharkey 2013-07-15 18:14:25 -07:00
parent 71ebe154a5
commit ba6ae8db13
7 changed files with 127 additions and 219 deletions

View file

@ -33,11 +33,8 @@
// #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;
@ -46,6 +43,18 @@ DirectVolume::DirectVolume(VolumeManager *vm, const char *label,
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);
}
@ -62,10 +71,6 @@ int DirectVolume::addPath(const char *path) {
return 0;
}
void DirectVolume::setFlags(int flags) {
mFlags = flags;
}
dev_t DirectVolume::getDiskDevice() {
return MKDEV(mDiskMajor, mDiskMinor);
}
@ -119,7 +124,7 @@ int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
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);
}
@ -286,7 +291,7 @@ void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) {
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);
@ -317,7 +322,7 @@ void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt
*/
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);
@ -452,7 +457,7 @@ int DirectVolume::getVolInfo(struct volume_info *v)
{
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;

View file

@ -29,6 +29,9 @@ class DirectVolume : public Volume {
public:
static const int MAX_PARTITIONS = 32;
protected:
const char* mMountpoint;
const char* mFuseMountpoint;
PathCollection *mPaths;
int mDiskMajor;
int mDiskMinor;
@ -42,18 +45,20 @@ protected:
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);

View file

@ -37,6 +37,7 @@
#define LOG_TAG "Vold"
#include <cutils/fs.h>
#include <cutils/log.h>
#include "Volume.h"
@ -51,21 +52,14 @@ extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
/*
* 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
@ -111,26 +105,25 @@ static const char *stateToStr(int state) {
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");
/*
@ -188,7 +181,7 @@ void Volume::setState(int state) {
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,
@ -292,12 +285,15 @@ int Volume::mountVol() {
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, "");
@ -306,10 +302,10 @@ int Volume::mountVol() {
* 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);
@ -337,13 +333,12 @@ int Volume::mountVol() {
}
/* 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];
@ -409,49 +404,28 @@ int Volume::mountVol() {
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;
@ -463,103 +437,33 @@ int Volume::mountVol() {
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)) {
snprintf(legacy_path, PATH_MAX, "%s/android_secure", getMountpoint());
snprintf(secure_path, PATH_MAX, "%s/.android_secure", getMountpoint());
// 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));
}
}
/*
* 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;
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;
}
}
/*
* 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;
@ -597,6 +501,9 @@ int Volume::doUnmount(const char *path, bool force) {
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;
@ -606,35 +513,32 @@ int Volume::unmountVol(bool force, bool revert) {
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
@ -650,25 +554,13 @@ int Volume::unmountVol(bool force, bool 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;
@ -676,6 +568,7 @@ out_nomedia:
setState(Volume::State_NoMedia);
return -1;
}
int Volume::initializeMbr(const char *deviceNode) {
struct disk_info dinfo;

View file

@ -18,6 +18,7 @@
#define _VOLUME_H
#include <utils/List.h>
#include <fs_mgr.h>
class NetlinkEvent;
class VolumeManager;
@ -25,6 +26,7 @@ class VolumeManager;
class Volume {
private:
int mState;
int mFlags;
public:
static const int State_Init = -1;
@ -38,9 +40,8 @@ public:
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;
@ -49,7 +50,6 @@ public:
protected:
char *mLabel;
char *mMountpoint;
VolumeManager *mVm;
bool mDebug;
int mPartIdx;
@ -62,7 +62,7 @@ protected:
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();
@ -70,8 +70,12 @@ public:
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();
@ -89,16 +93,14 @@ protected:
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();
};

View file

@ -159,7 +159,7 @@ int VolumeManager::listVolumes(SocketClient *cli) {
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);
@ -1054,7 +1054,7 @@ Volume* VolumeManager::getVolumeForFile(const char *fileName) {
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;
}
@ -1512,7 +1512,7 @@ Volume *VolumeManager::lookupVolume(const char *label) {
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()))
@ -1570,7 +1570,7 @@ int VolumeManager::cleanupAsec(Volume *v, bool force) {
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;

View file

@ -127,8 +127,10 @@ struct volume_info {
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" {

View file

@ -174,16 +174,6 @@ static int process_config(VolumeManager *vm)
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;
@ -191,7 +181,18 @@ static int process_config(VolumeManager *vm)
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);
}