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
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 813d831..fddee01 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -148,6 +148,9 @@
     } 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 @@
             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());
 
diff --git a/Disk.cpp b/Disk.cpp
index 51eeba8..5e222b3 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -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 @@
     }
 
     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 @@
     }
 
     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 @@
         }
     }
 
+#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;
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index dc746cf..025d2eb 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -124,18 +124,23 @@
         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
diff --git a/ResponseCode.h b/ResponseCode.h
index cdb4a79..2430f99 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -69,8 +69,7 @@
     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;
diff --git a/VolumeBase.cpp b/VolumeBase.cpp
index 3b49b0d..2db5afe 100644
--- a/VolumeBase.cpp
+++ b/VolumeBase.cpp
@@ -36,7 +36,7 @@
 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 @@
     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::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 @@
 
     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 @@
 
     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 @@
         return -EBUSY;
     }
 
-    setState(State::kMounting);
+    setState(State::kChecking);
     status_t res = doMount();
     if (res == OK) {
         setState(State::kMounted);
@@ -184,7 +196,7 @@
         return -EBUSY;
     }
 
-    setState(State::kUnmounting);
+    setState(State::kEjecting);
 
     for (auto vol : mVolumes) {
         if (vol->destroy()) {
diff --git a/VolumeBase.h b/VolumeBase.h
index e7c7836..1010e94 100644
--- a/VolumeBase.h
+++ b/VolumeBase.h
@@ -55,7 +55,7 @@
         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 @@
     };
 
     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 @@
 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 */
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index dcadd14..bbafa42 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -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 @@
     return buffer;
 }
 
-void VolumeManager::setDebug(bool enable) {
+int VolumeManager::setDebug(bool enable) {
     mDebug = enable;
+    return 0;
 }
 
 int VolumeManager::start() {
@@ -273,10 +272,11 @@
 }
 
 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"));
diff --git a/VolumeManager.h b/VolumeManager.h
index 06d0ce3..44920e0 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -159,7 +159,7 @@
     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; }