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