VolumeBase.cpp revision 11c2d380a786d9e304416be98881b90b74ff666d
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
33namespace android {
34namespace vold {
35
36VolumeBase::VolumeBase(Type type) :
37        mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState(
38                State::kUnmounted), mSilent(false) {
39}
40
41VolumeBase::~VolumeBase() {
42    CHECK(!mCreated);
43}
44
45void VolumeBase::setState(State state) {
46    mState = state;
47    notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
48}
49
50status_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
60status_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
70status_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
80status_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
90status_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
100status_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
110status_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
121status_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
132void VolumeBase::notifyEvent(int event) {
133    if (mSilent) return;
134    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
135            getId().c_str(), false);
136}
137
138void 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
144void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
145    mVolumes.push_back(volume);
146}
147
148void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
149    mVolumes.remove(volume);
150}
151
152std::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
161status_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
172status_t VolumeBase::doCreate() {
173    return OK;
174}
175
176status_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
192status_t VolumeBase::doDestroy() {
193    return OK;
194}
195
196status_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
213status_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
233status_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
249status_t VolumeBase::doFormat(const std::string& fsType) {
250    return -ENOTSUP;
251}
252
253}  // namespace vold
254}  // namespace android
255