Volumes know parent disks; unsupported disks.

This is cleaner and more direct than the reverse of having the disk
publish child volume membership.  Rename state constants to match
public API.  Add state representing bad removal.  Make it clear that
volume flags are related to mounting.

Send new unsupported disk event when we finish scanning an entire
disk and have no meaningful volumes.

Bug: 19993667
Change-Id: I08a91452ff561171a484d1da5745293ec893aec0
This commit is contained in:
Jeff Sharkey 2015-04-17 17:35:20 -07:00
parent 7d9d011865
commit f1b996df6f
8 changed files with 84 additions and 57 deletions

View file

@ -148,6 +148,9 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
} else if (cmd == "shutdown") {
return sendGenericOkFail(cli, vm->shutdown());
} else if (cmd == "debug") {
return sendGenericOkFail(cli, vm->setDebug(true));
} else if (cmd == "partition" && argc > 3) {
// partition [diskId] [public|private|mixed] [ratio]
std::string id(argv[2]);
@ -191,15 +194,15 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
int flags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t user = (argc > 4) ? atoi(argv[4]) : -1;
int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
if (flags & android::vold::VolumeBase::Flags::kPrimary) {
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
vol->setFlags(flags);
vol->setUser(user);
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
return sendGenericOkFail(cli, vol->mount());

View file

@ -36,6 +36,8 @@
#include <sys/stat.h>
#include <sys/mount.h>
#define ENTIRE_DEVICE_FALLBACK 0
using android::base::ReadFileToString;
using android::base::WriteStringToFile;
using android::base::StringPrintf;
@ -125,8 +127,8 @@ void Disk::createPublicVolume(dev_t device) {
}
mVolumes.push_back(vol);
vol->setDiskId(getId());
vol->create();
notifyEvent(ResponseCode::DiskVolumeCreated, vol->getId());
}
void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
@ -157,14 +159,13 @@ void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
}
mVolumes.push_back(vol);
vol->setDiskId(getId());
vol->create();
notifyEvent(ResponseCode::DiskVolumeCreated, vol->getId());
}
void Disk::destroyAllVolumes() {
for (auto vol : mVolumes) {
vol->destroy();
notifyEvent(ResponseCode::DiskVolumeDestroyed, vol->getId());
}
mVolumes.clear();
}
@ -295,11 +296,19 @@ status_t Disk::readPartitions() {
}
}
#if ENTIRE_DEVICE_FALLBACK
// Ugly last ditch effort, treat entire disk as partition
if (table == Table::kUnknown || !foundParts) {
// TODO: use blkid to confirm filesystem before doing this
LOG(WARNING) << mId << " has unknown partition table; trying entire device";
createPublicVolume(mDevice);
}
#endif
// Well this is embarrassing, we can't handle the disk
if (mVolumes.size() == 0) {
notifyEvent(ResponseCode::DiskUnsupported);
}
mJustPartitioned = false;
return OK;

View file

@ -124,18 +124,23 @@ status_t PublicVolume::doMount() {
return -EIO;
}
if (getFlags() & Flags::kPrimary) {
if (getMountFlags() & MountFlags::kPrimary) {
initAsecStage();
}
// Only need to spin up FUSE when visible
if (!(getFlags() & Flags::kVisible)) {
return OK;
}
// TODO: teach FUSE daemon to protect itself with user-specific GID
if (!(mFusePid = fork())) {
if (getFlags() & Flags::kPrimary) {
if (!(getMountFlags() & MountFlags::kVisible)) {
// TODO: mount so that only system apps can access
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
mRawPath.c_str(),
mFusePath.c_str(),
NULL)) {
PLOG(ERROR) << "Failed to exec";
}
} else if (getMountFlags() & MountFlags::kPrimary) {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW

View file

@ -69,8 +69,7 @@ public:
static const int DiskCreated = 640;
static const int DiskSizeChanged = 641;
static const int DiskLabelChanged = 642;
static const int DiskVolumeCreated = 643;
static const int DiskVolumeDestroyed = 644;
static const int DiskUnsupported = 643;
static const int DiskDestroyed = 649;
static const int VolumeCreated = 650;

View file

@ -36,7 +36,7 @@ namespace android {
namespace vold {
VolumeBase::VolumeBase(Type type) :
mType(type), mFlags(0), mUser(-1), mCreated(false), mState(
mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState(
State::kUnmounted), mSilent(false) {
}
@ -49,23 +49,33 @@ void VolumeBase::setState(State state) {
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
}
status_t VolumeBase::setFlags(int flags) {
if (mState != State::kUnmounted) {
LOG(WARNING) << getId() << " flags change requires state unmounted";
status_t VolumeBase::setDiskId(const std::string& diskId) {
if (mCreated) {
LOG(WARNING) << getId() << " diskId change requires destroyed";
return -EBUSY;
}
mFlags = flags;
mDiskId = diskId;
return OK;
}
status_t VolumeBase::setUser(userid_t user) {
if (mState != State::kUnmounted) {
LOG(WARNING) << getId() << " user change requires state unmounted";
status_t VolumeBase::setMountFlags(int mountFlags) {
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable";
return -EBUSY;
}
mUser = user;
mMountFlags = mountFlags;
return OK;
}
status_t VolumeBase::setMountUserId(userid_t mountUserId) {
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
LOG(WARNING) << getId() << " user change requires state unmounted or unmountable";
return -EBUSY;
}
mMountUserId = mountUserId;
return OK;
}
@ -90,8 +100,8 @@ status_t VolumeBase::setId(const std::string& id) {
}
status_t VolumeBase::setPath(const std::string& path) {
if (mState != State::kMounting) {
LOG(WARNING) << getId() << " path change requires state mounting";
if (mState != State::kChecking) {
LOG(WARNING) << getId() << " path change requires state checking";
return -EBUSY;
}
@ -134,7 +144,7 @@ status_t VolumeBase::create() {
mCreated = true;
status_t res = doCreate();
notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d", mType));
notifyEvent(ResponseCode::VolumeCreated, StringPrintf("%d %s", mType, mDiskId.c_str()));
setState(State::kUnmounted);
return res;
}
@ -148,9 +158,11 @@ status_t VolumeBase::destroy() {
if (mState == State::kMounted) {
unmount();
setState(State::kBadRemoval);
} else {
setState(State::kRemoved);
}
setState(State::kRemoved);
notifyEvent(ResponseCode::VolumeDestroyed);
status_t res = doDestroy();
mCreated = false;
@ -167,7 +179,7 @@ status_t VolumeBase::mount() {
return -EBUSY;
}
setState(State::kMounting);
setState(State::kChecking);
status_t res = doMount();
if (res == OK) {
setState(State::kMounted);
@ -184,7 +196,7 @@ status_t VolumeBase::unmount() {
return -EBUSY;
}
setState(State::kUnmounting);
setState(State::kEjecting);
for (auto vol : mVolumes) {
if (vol->destroy()) {

View file

@ -55,7 +55,7 @@ public:
kObb,
};
enum Flags {
enum MountFlags {
/* Flag that volume is primary external storage */
kPrimary = 1 << 0,
/* Flag that volume is visible to normal apps */
@ -63,31 +63,28 @@ public:
};
enum class State {
/* Next states: mounting, formatting */
kUnmounted = 0,
/* Next states: mounted, unmountable */
kMounting,
/* Next states: unmounting */
kChecking,
kMounted,
/* Next states: unmounted */
kMountedReadOnly,
kFormatting,
/* Next states: unmounted */
kUnmounting,
/* Next states: mounting, formatting */
kEjecting,
kUnmountable,
/* Next states: none */
kRemoved,
kBadRemoval,
};
const std::string& getId() { return mId; }
const std::string& getDiskId() { return mDiskId; }
Type getType() { return mType; }
int getFlags() { return mFlags; }
userid_t getUser() { return mUser; }
int getMountFlags() { return mMountFlags; }
userid_t getMountUserId() { return mMountUserId; }
State getState() { return mState; }
const std::string& getPath() { return mPath; }
status_t setFlags(int flags);
status_t setUser(userid_t user);
status_t setDiskId(const std::string& diskId);
status_t setMountFlags(int mountFlags);
status_t setMountUserId(userid_t mountUserId);
status_t setSilent(bool silent);
void addVolume(const std::shared_ptr<VolumeBase>& volume);
@ -119,12 +116,14 @@ protected:
private:
/* ID that uniquely references volume while alive */
std::string mId;
/* ID that uniquely references parent disk while alive */
std::string mDiskId;
/* Volume type */
Type mType;
/* Flags applicable to volume */
int mFlags;
/* Flags used when mounting this volume */
int mMountFlags;
/* User that owns this volume, otherwise -1 */
userid_t mUser;
userid_t mMountUserId;
/* Flag indicating object is created */
bool mCreated;
/* Current state of volume */

View file

@ -59,8 +59,6 @@
#include "VoldUtil.h"
#include "cryptfs.h"
#define DEBUG_NETLINK 0
#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
@ -248,8 +246,9 @@ char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
return buffer;
}
void VolumeManager::setDebug(bool enable) {
int VolumeManager::setDebug(bool enable) {
mDebug = enable;
return 0;
}
int VolumeManager::start() {
@ -273,10 +272,11 @@ int VolumeManager::stop() {
}
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
#if DEBUG_NETLINK
LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
evt->dump();
#endif
if (mDebug) {
LOG(VERBOSE) << "----------------";
LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
evt->dump();
}
std::string eventPath(evt->findParam("DEVPATH"));
std::string devType(evt->findParam("DEVTYPE"));

View file

@ -159,7 +159,7 @@ public:
int unmountLoopImage(const char *containerId, const char *loopId,
const char *fileName, const char *mountPoint, bool force);
void setDebug(bool enable);
int setDebug(bool enable);
void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
SocketListener *getBroadcaster() { return mBroadcaster; }