1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "Utils.h" 18#include "VolumeBase.h" 19#include "VolumeManager.h" 20 21#include <android-base/stringprintf.h> 22#include <android-base/logging.h> 23 24#include <fcntl.h> 25#include <stdlib.h> 26#include <sys/mount.h> 27#include <sys/stat.h> 28#include <sys/types.h> 29 30using android::base::StringPrintf; 31 32namespace android { 33namespace vold { 34 35VolumeBase::VolumeBase(Type type) : 36 mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState( 37 State::kUnmounted), mSilent(false) { 38} 39 40VolumeBase::~VolumeBase() { 41 CHECK(!mCreated); 42} 43 44void VolumeBase::setState(State state) { 45 mState = state; 46 47 auto listener = getListener(); 48 if (listener) listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState)); 49} 50 51status_t VolumeBase::setDiskId(const std::string& diskId) { 52 if (mCreated) { 53 LOG(WARNING) << getId() << " diskId change requires destroyed"; 54 return -EBUSY; 55 } 56 57 mDiskId = diskId; 58 return OK; 59} 60 61status_t VolumeBase::setPartGuid(const std::string& partGuid) { 62 if (mCreated) { 63 LOG(WARNING) << getId() << " partGuid change requires destroyed"; 64 return -EBUSY; 65 } 66 67 mPartGuid = partGuid; 68 return OK; 69} 70 71status_t VolumeBase::setMountFlags(int mountFlags) { 72 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 73 LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable"; 74 return -EBUSY; 75 } 76 77 mMountFlags = mountFlags; 78 return OK; 79} 80 81status_t VolumeBase::setMountUserId(userid_t mountUserId) { 82 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 83 LOG(WARNING) << getId() << " user change requires state unmounted or unmountable"; 84 return -EBUSY; 85 } 86 87 mMountUserId = mountUserId; 88 return OK; 89} 90 91status_t VolumeBase::setSilent(bool silent) { 92 if (mCreated) { 93 LOG(WARNING) << getId() << " silence change requires destroyed"; 94 return -EBUSY; 95 } 96 97 mSilent = silent; 98 return OK; 99} 100 101status_t VolumeBase::setId(const std::string& id) { 102 if (mCreated) { 103 LOG(WARNING) << getId() << " id change requires not created"; 104 return -EBUSY; 105 } 106 107 mId = id; 108 return OK; 109} 110 111status_t VolumeBase::setPath(const std::string& path) { 112 if (mState != State::kChecking) { 113 LOG(WARNING) << getId() << " path change requires state checking"; 114 return -EBUSY; 115 } 116 117 mPath = path; 118 119 auto listener = getListener(); 120 if (listener) listener->onVolumePathChanged(getId(), mPath); 121 122 return OK; 123} 124 125status_t VolumeBase::setInternalPath(const std::string& internalPath) { 126 if (mState != State::kChecking) { 127 LOG(WARNING) << getId() << " internal path change requires state checking"; 128 return -EBUSY; 129 } 130 131 mInternalPath = internalPath; 132 133 auto listener = getListener(); 134 if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath); 135 136 return OK; 137} 138 139android::sp<android::os::IVoldListener> VolumeBase::getListener() { 140 if (mSilent) { 141 return nullptr; 142 } else { 143 return VolumeManager::Instance()->getListener(); 144 } 145} 146 147void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) { 148 mVolumes.push_back(volume); 149} 150 151void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) { 152 mVolumes.remove(volume); 153} 154 155std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) { 156 for (auto vol : mVolumes) { 157 if (vol->getId() == id) { 158 return vol; 159 } 160 } 161 return nullptr; 162} 163 164status_t VolumeBase::create() { 165 CHECK(!mCreated); 166 167 mCreated = true; 168 status_t res = doCreate(); 169 170 auto listener = getListener(); 171 if (listener) listener->onVolumeCreated(getId(), 172 static_cast<int32_t>(mType), mDiskId, mPartGuid); 173 174 setState(State::kUnmounted); 175 return res; 176} 177 178status_t VolumeBase::doCreate() { 179 return OK; 180} 181 182status_t VolumeBase::destroy() { 183 CHECK(mCreated); 184 185 if (mState == State::kMounted) { 186 unmount(); 187 setState(State::kBadRemoval); 188 } else { 189 setState(State::kRemoved); 190 } 191 192 193 auto listener = getListener(); 194 if (listener) listener->onVolumeDestroyed(getId()); 195 196 status_t res = doDestroy(); 197 mCreated = false; 198 return res; 199} 200 201status_t VolumeBase::doDestroy() { 202 return OK; 203} 204 205status_t VolumeBase::mount() { 206 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 207 LOG(WARNING) << getId() << " mount requires state unmounted or unmountable"; 208 return -EBUSY; 209 } 210 211 setState(State::kChecking); 212 status_t res = doMount(); 213 if (res == OK) { 214 setState(State::kMounted); 215 } else { 216 setState(State::kUnmountable); 217 } 218 219 return res; 220} 221 222status_t VolumeBase::unmount() { 223 if (mState != State::kMounted) { 224 LOG(WARNING) << getId() << " unmount requires state mounted"; 225 return -EBUSY; 226 } 227 228 setState(State::kEjecting); 229 for (const auto& vol : mVolumes) { 230 if (vol->destroy()) { 231 LOG(WARNING) << getId() << " failed to destroy " << vol->getId() 232 << " stacked above"; 233 } 234 } 235 mVolumes.clear(); 236 237 status_t res = doUnmount(); 238 setState(State::kUnmounted); 239 return res; 240} 241 242status_t VolumeBase::format(const std::string& fsType) { 243 if (mState == State::kMounted) { 244 unmount(); 245 } 246 247 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 248 LOG(WARNING) << getId() << " format requires state unmounted or unmountable"; 249 return -EBUSY; 250 } 251 252 setState(State::kFormatting); 253 status_t res = doFormat(fsType); 254 setState(State::kUnmounted); 255 return res; 256} 257 258status_t VolumeBase::doFormat(const std::string& fsType) { 259 return -ENOTSUP; 260} 261 262} // namespace vold 263} // namespace android 264