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
30 using android::base::StringPrintf;
31
32 namespace android {
33 namespace vold {
34
VolumeBase(Type type)35 VolumeBase::VolumeBase(Type type) :
36 mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState(
37 State::kUnmounted), mSilent(false) {
38 }
39
~VolumeBase()40 VolumeBase::~VolumeBase() {
41 CHECK(!mCreated);
42 }
43
setState(State state)44 void 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
setDiskId(const std::string & diskId)51 status_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
setPartGuid(const std::string & partGuid)61 status_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
setMountFlags(int mountFlags)71 status_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
setMountUserId(userid_t mountUserId)81 status_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
setSilent(bool silent)91 status_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
setId(const std::string & id)101 status_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
setPath(const std::string & path)111 status_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
setInternalPath(const std::string & internalPath)125 status_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
getListener()139 android::sp<android::os::IVoldListener> VolumeBase::getListener() {
140 if (mSilent) {
141 return nullptr;
142 } else {
143 return VolumeManager::Instance()->getListener();
144 }
145 }
146
addVolume(const std::shared_ptr<VolumeBase> & volume)147 void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
148 mVolumes.push_back(volume);
149 }
150
removeVolume(const std::shared_ptr<VolumeBase> & volume)151 void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
152 mVolumes.remove(volume);
153 }
154
findVolume(const std::string & id)155 std::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
create()164 status_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
doCreate()178 status_t VolumeBase::doCreate() {
179 return OK;
180 }
181
destroy()182 status_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
doDestroy()201 status_t VolumeBase::doDestroy() {
202 return OK;
203 }
204
mount()205 status_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
unmount()222 status_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
format(const std::string & fsType)242 status_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
doFormat(const std::string & fsType)258 status_t VolumeBase::doFormat(const std::string& fsType) {
259 return -ENOTSUP;
260 }
261
262 } // namespace vold
263 } // namespace android
264