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#include "ResponseCode.h" 21 22#include <android-base/stringprintf.h> 23#include <android-base/logging.h> 24 25#include <fcntl.h> 26#include <stdlib.h> 27#include <sys/mount.h> 28#include <sys/stat.h> 29#include <sys/types.h> 30 31using android::base::StringPrintf; 32 33#define DEBUG 1 34 35namespace android { 36namespace vold { 37 38VolumeBase::VolumeBase(Type type) : 39 mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState( 40 State::kUnmounted), mSilent(false) { 41} 42 43VolumeBase::~VolumeBase() { 44 CHECK(!mCreated); 45} 46 47void VolumeBase::setState(State state) { 48 mState = state; 49 notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState)); 50} 51 52status_t VolumeBase::setDiskId(const std::string& diskId) { 53 if (mCreated) { 54 LOG(WARNING) << getId() << " diskId change requires destroyed"; 55 return -EBUSY; 56 } 57 58 mDiskId = diskId; 59 return OK; 60} 61 62status_t VolumeBase::setPartGuid(const std::string& partGuid) { 63 if (mCreated) { 64 LOG(WARNING) << getId() << " partGuid change requires destroyed"; 65 return -EBUSY; 66 } 67 68 mPartGuid = partGuid; 69 return OK; 70} 71 72status_t VolumeBase::setMountFlags(int mountFlags) { 73 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 74 LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable"; 75 return -EBUSY; 76 } 77 78 mMountFlags = mountFlags; 79 return OK; 80} 81 82status_t VolumeBase::setMountUserId(userid_t mountUserId) { 83 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 84 LOG(WARNING) << getId() << " user change requires state unmounted or unmountable"; 85 return -EBUSY; 86 } 87 88 mMountUserId = mountUserId; 89 return OK; 90} 91 92status_t VolumeBase::setSilent(bool silent) { 93 if (mCreated) { 94 LOG(WARNING) << getId() << " silence change requires destroyed"; 95 return -EBUSY; 96 } 97 98 mSilent = silent; 99 return OK; 100} 101 102status_t VolumeBase::setId(const std::string& id) { 103 if (mCreated) { 104 LOG(WARNING) << getId() << " id change requires not created"; 105 return -EBUSY; 106 } 107 108 mId = id; 109 return OK; 110} 111 112status_t VolumeBase::setPath(const std::string& path) { 113 if (mState != State::kChecking) { 114 LOG(WARNING) << getId() << " path change requires state checking"; 115 return -EBUSY; 116 } 117 118 mPath = path; 119 notifyEvent(ResponseCode::VolumePathChanged, mPath); 120 return OK; 121} 122 123status_t VolumeBase::setInternalPath(const std::string& internalPath) { 124 if (mState != State::kChecking) { 125 LOG(WARNING) << getId() << " internal path change requires state checking"; 126 return -EBUSY; 127 } 128 129 mInternalPath = internalPath; 130 notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath); 131 return OK; 132} 133 134void VolumeBase::notifyEvent(int event) { 135 if (mSilent) return; 136 VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event, 137 getId().c_str(), false); 138} 139 140void VolumeBase::notifyEvent(int event, const std::string& value) { 141 if (mSilent) return; 142 VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event, 143 StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false); 144} 145 146void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) { 147 mVolumes.push_back(volume); 148} 149 150void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) { 151 mVolumes.remove(volume); 152} 153 154std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) { 155 for (auto vol : mVolumes) { 156 if (vol->getId() == id) { 157 return vol; 158 } 159 } 160 return nullptr; 161} 162 163status_t VolumeBase::create() { 164 CHECK(!mCreated); 165 166 mCreated = true; 167 status_t res = doCreate(); 168 notifyEvent(ResponseCode::VolumeCreated, 169 StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); 170 setState(State::kUnmounted); 171 return res; 172} 173 174status_t VolumeBase::doCreate() { 175 return OK; 176} 177 178status_t VolumeBase::destroy() { 179 CHECK(mCreated); 180 181 if (mState == State::kMounted) { 182 unmount(); 183 setState(State::kBadRemoval); 184 } else { 185 setState(State::kRemoved); 186 } 187 188 notifyEvent(ResponseCode::VolumeDestroyed); 189 status_t res = doDestroy(); 190 mCreated = false; 191 return res; 192} 193 194status_t VolumeBase::doDestroy() { 195 return OK; 196} 197 198status_t VolumeBase::mount() { 199 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 200 LOG(WARNING) << getId() << " mount requires state unmounted or unmountable"; 201 return -EBUSY; 202 } 203 204 setState(State::kChecking); 205 status_t res = doMount(); 206 if (res == OK) { 207 setState(State::kMounted); 208 } else { 209 setState(State::kUnmountable); 210 } 211 212 return res; 213} 214 215status_t VolumeBase::unmount() { 216 if (mState != State::kMounted) { 217 LOG(WARNING) << getId() << " unmount requires state mounted"; 218 return -EBUSY; 219 } 220 221 setState(State::kEjecting); 222 for (auto vol : mVolumes) { 223 if (vol->destroy()) { 224 LOG(WARNING) << getId() << " failed to destroy " << vol->getId() 225 << " stacked above"; 226 } 227 } 228 mVolumes.clear(); 229 230 status_t res = doUnmount(); 231 setState(State::kUnmounted); 232 return res; 233} 234 235status_t VolumeBase::format(const std::string& fsType) { 236 if (mState == State::kMounted) { 237 unmount(); 238 } 239 240 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { 241 LOG(WARNING) << getId() << " format requires state unmounted or unmountable"; 242 return -EBUSY; 243 } 244 245 setState(State::kFormatting); 246 status_t res = doFormat(fsType); 247 setState(State::kUnmounted); 248 return res; 249} 250 251status_t VolumeBase::doFormat(const std::string& fsType) { 252 return -ENOTSUP; 253} 254 255} // namespace vold 256} // namespace android 257