platform_system_vold/model/VolumeBase.h
Martijn Coenen 5ec8658abc Introduce postMount() VolumeBase helper.
When we're mounting a private volume, we create stacked emulated volumes
on top of it. Due to the ordering there, we would broadcast the emulated
volumes being created *before* the "mounted" status update. This in turn
could cause us to try and mount these emulated volumes before the
underlying private volume is really mounted. This is problematic in
particular on devices that support a filesystem keyring, where we need
to do some additional setup before the devices can be used.

While we could modify StorageManagerService to delay the mount, a safer
fix at this stage of the release is to just fix the ordering of these
events. To achieve that, add a simple postMount() helper, that is called
after a succesful mount. This allows us to setup the volume properly
before trying to mount any stacked volumes.

Bug: 151079464
Test: atest AdoptableHostTest
Change-Id: I2cc4113d4d71d89aa629bb9c0fa9be441355c079
2020-05-04 15:09:32 +02:00

170 lines
5.2 KiB
C++

/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_VOLD_VOLUME_BASE_H
#define ANDROID_VOLD_VOLUME_BASE_H
#include "Utils.h"
#include "android/os/IVoldListener.h"
#include "android/os/IVoldMountCallback.h"
#include <cutils/multiuser.h>
#include <utils/Errors.h>
#include <sys/types.h>
#include <list>
#include <string>
static constexpr userid_t USER_UNKNOWN = ((userid_t)-1);
namespace android {
namespace vold {
/*
* Representation of a mounted volume ready for presentation.
*
* Various subclasses handle the different mounting prerequisites, such as
* encryption details, etc. Volumes can also be "stacked" above other
* volumes to help communicate dependencies. For example, an ASEC volume
* can be stacked on a vfat volume.
*
* Mounted volumes can be asked to manage bind mounts to present themselves
* to specific users on the device.
*
* When an unmount is requested, the volume recursively unmounts any stacked
* volumes and removes any bind mounts before finally unmounting itself.
*/
class VolumeBase {
public:
virtual ~VolumeBase();
enum class Type {
kPublic = 0,
kPrivate,
kEmulated,
kAsec,
kObb,
kStub,
};
enum MountFlags {
/* Flag that volume is primary external storage */
kPrimary = 1 << 0,
/* Flag that volume is visible to normal apps */
kVisible = 1 << 1,
};
enum class State {
kUnmounted = 0,
kChecking,
kMounted,
kMountedReadOnly,
kFormatting,
kEjecting,
kUnmountable,
kRemoved,
kBadRemoval,
};
const std::string& getId() const { return mId; }
const std::string& getDiskId() const { return mDiskId; }
const std::string& getPartGuid() const { return mPartGuid; }
Type getType() const { return mType; }
int getMountFlags() const { return mMountFlags; }
userid_t getMountUserId() const { return mMountUserId; }
State getState() const { return mState; }
const std::string& getPath() const { return mPath; }
const std::string& getInternalPath() const { return mInternalPath; }
const std::list<std::shared_ptr<VolumeBase>>& getVolumes() const { return mVolumes; }
status_t setDiskId(const std::string& diskId);
status_t setPartGuid(const std::string& partGuid);
status_t setMountFlags(int mountFlags);
status_t setMountUserId(userid_t mountUserId);
status_t setMountCallback(const android::sp<android::os::IVoldMountCallback>& callback);
status_t setSilent(bool silent);
void addVolume(const std::shared_ptr<VolumeBase>& volume);
void removeVolume(const std::shared_ptr<VolumeBase>& volume);
std::shared_ptr<VolumeBase> findVolume(const std::string& id);
bool isEmulated() { return mType == Type::kEmulated; }
status_t create();
status_t destroy();
status_t mount();
status_t unmount();
status_t format(const std::string& fsType);
virtual std::string getRootPath() const;
std::ostream& operator<<(std::ostream& stream) const;
protected:
explicit VolumeBase(Type type);
virtual status_t doCreate();
virtual status_t doDestroy();
virtual status_t doMount() = 0;
virtual void doPostMount();
virtual status_t doUnmount() = 0;
virtual status_t doFormat(const std::string& fsType);
status_t setId(const std::string& id);
status_t setPath(const std::string& path);
status_t setInternalPath(const std::string& internalPath);
android::sp<android::os::IVoldListener> getListener() const;
android::sp<android::os::IVoldMountCallback> getMountCallback() const;
private:
/* ID that uniquely references volume while alive */
std::string mId;
/* ID that uniquely references parent disk while alive */
std::string mDiskId;
/* Partition GUID of this volume */
std::string mPartGuid;
/* Volume type */
Type mType;
/* Flags used when mounting this volume */
int mMountFlags;
/* User that owns this volume, otherwise -1 */
userid_t mMountUserId;
/* Flag indicating object is created */
bool mCreated;
/* Current state of volume */
State mState;
/* Path to mounted volume */
std::string mPath;
/* Path to internal backing storage */
std::string mInternalPath;
/* Flag indicating that volume should emit no events */
bool mSilent;
android::sp<android::os::IVoldMountCallback> mMountCallback;
/* Volumes stacked on top of this volume */
std::list<std::shared_ptr<VolumeBase>> mVolumes;
void setState(State state);
DISALLOW_COPY_AND_ASSIGN(VolumeBase);
};
} // namespace vold
} // namespace android
#endif