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