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 "VolumeBase.h"
18 #include "Utils.h"
19 #include "VolumeManager.h"
20
21 #include <android-base/logging.h>
22 #include <android-base/stringprintf.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
30 using android::base::StringPrintf;
31
32 namespace android {
33 namespace vold {
34
VolumeBase(Type type)35 VolumeBase::VolumeBase(Type type)
36 : mType(type),
37 mMountFlags(0),
38 mMountUserId(USER_UNKNOWN),
39 mCreated(false),
40 mState(State::kUnmounted),
41 mSilent(false) {}
42
~VolumeBase()43 VolumeBase::~VolumeBase() {
44 CHECK(!mCreated);
45 }
46
setState(State state)47 void VolumeBase::setState(State state) {
48 mState = state;
49
50 auto listener = getListener();
51 if (listener) {
52 listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState));
53 }
54 }
55
setDiskId(const std::string & diskId)56 status_t VolumeBase::setDiskId(const std::string& diskId) {
57 if (mCreated) {
58 LOG(WARNING) << getId() << " diskId change requires destroyed";
59 return -EBUSY;
60 }
61
62 mDiskId = diskId;
63 return OK;
64 }
65
setPartGuid(const std::string & partGuid)66 status_t VolumeBase::setPartGuid(const std::string& partGuid) {
67 if (mCreated) {
68 LOG(WARNING) << getId() << " partGuid change requires destroyed";
69 return -EBUSY;
70 }
71
72 mPartGuid = partGuid;
73 return OK;
74 }
75
setMountFlags(int mountFlags)76 status_t VolumeBase::setMountFlags(int mountFlags) {
77 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
78 LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable";
79 return -EBUSY;
80 }
81
82 mMountFlags = mountFlags;
83 return OK;
84 }
85
setMountUserId(userid_t mountUserId)86 status_t VolumeBase::setMountUserId(userid_t mountUserId) {
87 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
88 LOG(WARNING) << getId() << " user change requires state unmounted or unmountable";
89 return -EBUSY;
90 }
91
92 mMountUserId = mountUserId;
93 return OK;
94 }
95
setSilent(bool silent)96 status_t VolumeBase::setSilent(bool silent) {
97 if (mCreated) {
98 LOG(WARNING) << getId() << " silence change requires destroyed";
99 return -EBUSY;
100 }
101
102 mSilent = silent;
103 return OK;
104 }
105
setId(const std::string & id)106 status_t VolumeBase::setId(const std::string& id) {
107 if (mCreated) {
108 LOG(WARNING) << getId() << " id change requires not created";
109 return -EBUSY;
110 }
111
112 mId = id;
113 return OK;
114 }
115
setPath(const std::string & path)116 status_t VolumeBase::setPath(const std::string& path) {
117 if (mState != State::kChecking) {
118 LOG(WARNING) << getId() << " path change requires state checking";
119 return -EBUSY;
120 }
121
122 mPath = path;
123
124 auto listener = getListener();
125 if (listener) listener->onVolumePathChanged(getId(), mPath);
126
127 return OK;
128 }
129
setInternalPath(const std::string & internalPath)130 status_t VolumeBase::setInternalPath(const std::string& internalPath) {
131 if (mState != State::kChecking) {
132 LOG(WARNING) << getId() << " internal path change requires state checking";
133 return -EBUSY;
134 }
135
136 mInternalPath = internalPath;
137
138 auto listener = getListener();
139 if (listener) {
140 listener->onVolumeInternalPathChanged(getId(), mInternalPath);
141 }
142
143 return OK;
144 }
145
setMountCallback(const android::sp<android::os::IVoldMountCallback> & callback)146 status_t VolumeBase::setMountCallback(
147 const android::sp<android::os::IVoldMountCallback>& callback) {
148 mMountCallback = callback;
149 return OK;
150 }
151
getMountCallback() const152 sp<android::os::IVoldMountCallback> VolumeBase::getMountCallback() const {
153 return mMountCallback;
154 }
155
getListener() const156 android::sp<android::os::IVoldListener> VolumeBase::getListener() const {
157 if (mSilent) {
158 return nullptr;
159 } else {
160 return VolumeManager::Instance()->getListener();
161 }
162 }
163
addVolume(const std::shared_ptr<VolumeBase> & volume)164 void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
165 mVolumes.push_back(volume);
166 }
167
removeVolume(const std::shared_ptr<VolumeBase> & volume)168 void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
169 mVolumes.remove(volume);
170 }
171
findVolume(const std::string & id)172 std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) {
173 for (auto vol : mVolumes) {
174 if (vol->getId() == id) {
175 return vol;
176 }
177 }
178 return nullptr;
179 }
180
create()181 status_t VolumeBase::create() {
182 CHECK(!mCreated);
183
184 mCreated = true;
185 status_t res = doCreate();
186
187 auto listener = getListener();
188 if (listener) {
189 listener->onVolumeCreated(getId(), static_cast<int32_t>(mType), mDiskId, mPartGuid,
190 mMountUserId);
191 }
192
193 setState(State::kUnmounted);
194 return res;
195 }
196
doCreate()197 status_t VolumeBase::doCreate() {
198 return OK;
199 }
200
destroy()201 status_t VolumeBase::destroy() {
202 CHECK(mCreated);
203
204 if (mState == State::kMounted) {
205 unmount();
206 setState(State::kBadRemoval);
207 } else {
208 setState(State::kRemoved);
209 }
210
211 auto listener = getListener();
212 if (listener) {
213 listener->onVolumeDestroyed(getId());
214 }
215
216 status_t res = doDestroy();
217 mCreated = false;
218 return res;
219 }
220
doDestroy()221 status_t VolumeBase::doDestroy() {
222 return OK;
223 }
224
mount()225 status_t VolumeBase::mount() {
226 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
227 LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";
228 return -EBUSY;
229 }
230
231 setState(State::kChecking);
232 status_t res = doMount();
233 setState(res == OK ? State::kMounted : State::kUnmountable);
234
235 if (res == OK) {
236 doPostMount();
237 }
238 return res;
239 }
240
doPostMount()241 void VolumeBase::doPostMount() {}
242
unmount()243 status_t VolumeBase::unmount() {
244 if (mState != State::kMounted) {
245 LOG(WARNING) << getId() << " unmount requires state mounted";
246 return -EBUSY;
247 }
248
249 setState(State::kEjecting);
250 for (const auto& vol : mVolumes) {
251 if (vol->destroy()) {
252 LOG(WARNING) << getId() << " failed to destroy " << vol->getId() << " stacked above";
253 }
254 }
255 mVolumes.clear();
256
257 status_t res = doUnmount();
258 setState(State::kUnmounted);
259 return res;
260 }
261
format(const std::string & fsType)262 status_t VolumeBase::format(const std::string& fsType) {
263 if (mState == State::kMounted) {
264 unmount();
265 }
266
267 if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
268 LOG(WARNING) << getId() << " format requires state unmounted or unmountable";
269 return -EBUSY;
270 }
271
272 setState(State::kFormatting);
273 status_t res = doFormat(fsType);
274 setState(State::kUnmounted);
275 return res;
276 }
277
doFormat(const std::string & fsType)278 status_t VolumeBase::doFormat(const std::string& fsType) {
279 return -ENOTSUP;
280 }
281
getRootPath() const282 std::string VolumeBase::getRootPath() const {
283 // Usually the same as the internal path, except for emulated volumes.
284 return getInternalPath();
285 }
286
operator <<(std::ostream & stream) const287 std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
288 return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags
289 << ",mountUserId=" << mMountUserId << "}";
290 }
291
292 } // namespace vold
293 } // namespace android
294