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 31 using android::base::StringPrintf; 32 33 #define DEBUG 1 34 35 namespace android { 36 namespace vold { 37 38 VolumeBase::VolumeBase(Type type) : 39 mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState( 40 State::kUnmounted), mSilent(false) { 41 } 42 43 VolumeBase::~VolumeBase() { 44 CHECK(!mCreated); 45 } 46 47 void VolumeBase::setState(State state) { 48 mState = state; 49 notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState)); 50 } 51 52 status_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 62 status_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 72 status_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 82 status_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 92 status_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 102 status_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 112 status_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 123 status_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 134 void VolumeBase::notifyEvent(int event) { 135 if (mSilent) return; 136 VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event, 137 getId().c_str(), false); 138 } 139 140 void 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 146 void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) { 147 mVolumes.push_back(volume); 148 } 149 150 void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) { 151 mVolumes.remove(volume); 152 } 153 154 std::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 163 status_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 174 status_t VolumeBase::doCreate() { 175 return OK; 176 } 177 178 status_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 194 status_t VolumeBase::doDestroy() { 195 return OK; 196 } 197 198 status_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 215 status_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 235 status_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 251 status_t VolumeBase::doFormat(const std::string& fsType) { 252 return -ENOTSUP; 253 } 254 255 } // namespace vold 256 } // namespace android 257