Home | History | Annotate | Download | only in vold
      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