OSDN Git Service

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