Android9.0 外部存储浅析

2020-10-20  本文已影响0人  Boerma

Android9.0 外部存储浅析

vold进程

main函数

初始化VolumeManager,NetlinkManager等一系列基础动作。

 int main(int argc, char** argv) {
   
   //......
   
   /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    }

    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }

    if (android::base::GetBoolProperty("vold.debug", false)) {
        vm->setDebug(true);
    }

    if (vm->start()) {
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }
   
   //......
   
    ATRACE_BEGIN("NetlinkManager::start");
    if (nm->start()) {
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }
    ATRACE_END();
   
   //......
 }

vm->start()

进行预制存储的挂载

int VolumeManager::start() {
    ATRACE_NAME("VolumeManager::start");

    // Always start from a clean slate by unmounting everything in
    // directories that we own, in case we crashed.
    unmountAll();

    Devmapper::destroyAll();
    Loop::destroyAll();

    // Assume that we always have an emulated volume on internal
    // storage; the framework will decide if it should be mounted.
    CHECK(mInternalEmulated == nullptr);
    //这里是sdcard/emulated分区
    mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
            new android::vold::EmulatedVolume("/data/media"));
    mInternalEmulated->create();

    // Consider creating a virtual disk
    updateVirtualDisk();

    return 0;
}

nm->start()

与kennel建立联系

int NetlinkManager::start() {
    struct sockaddr_nl nladdr;
  
        //......
    //与kennel建立联系
    //......
  
        //上报事件关键
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        PLOG(ERROR) << "Unable to start NetlinkHandler";
        goto out;
    }
  
        //......
}

建立联系后,kennel的事件上报将会回调至NetlinkHandler中的onEvent函数

void NetlinkHandler::onEvent(NetlinkEvent *evt) {
    VolumeManager *vm = VolumeManager::Instance();
    const char *subsys = evt->getSubsystem();

    if (!subsys) {
        LOG(WARNING) << "No subsystem found in netlink event";
        return;
    }

    if (std::string(subsys) == "block") {
        vm->handleBlockEvent(evt);
    }
}

最终回到VolumeManager中的handleBlockEvent(NetlinkEvent *evt)函数

void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    std::lock_guard<std::mutex> lock(mLock);
  
    /*
    ......
    
    创建device信息
    
    ......
    */
  
    //区分事件
    switch (evt->getAction()) {
      case NetlinkEvent::Action::kAdd: {    //添加
          for (const auto& source : mDiskSources) {
              if (source->matches(eventPath)) {
                  // For now, assume that MMC and virtio-blk (the latter is
                  // emulator-specific; see Disk.cpp for details) devices are SD,
                  // and that everything else is USB
                  int flags = source->getFlags();
                  if (major == kMajorBlockMmc
                      || (android::vold::IsRunningInEmulator()
                      && major >= (int) kMajorBlockExperimentalMin
                      && major <= (int) kMajorBlockExperimentalMax)) {
                      flags |= android::vold::Disk::Flags::kSd;
                  } else {
                      flags |= android::vold::Disk::Flags::kUsb;
                  }

                  auto disk = new android::vold::Disk(eventPath, device,
                          source->getNickname(), flags);
                    //添加设备
                  handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
                  break;
              }
          }
          break;
      }
      case NetlinkEvent::Action::kChange: { //状态改变
          LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
          handleDiskChanged(device);
          break;
      }
      case NetlinkEvent::Action::kRemove: { ////移除
          handleDiskRemoved(device);
          break;
      }
      default: {
          LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
          break;
      }
    }
}

当一个外部存储插入设备后经过上报及区分后,调用handleDiskAdded函数

void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {
    // For security reasons, if secure keyguard is showing, wait
    // until the user unlocks the device to actually touch it
    if (mSecureKeyguardShowing) {
        LOG(INFO) << "Found disk at " << disk->getEventPath()
                << " but delaying scan due to secure keyguard";
        mPendingDisks.push_back(disk);
    } else {
        //disk进行初始化,disk基础信息,分区挂载等
        disk->create();
        mDisks.push_back(disk);
    }
}

disk->create()

status_t Disk::create() {
    CHECK(!mCreated);
    mCreated = true;

    //从这里将会调用frameworks层StorageManagerService中的实现函数
    auto listener = VolumeManager::Instance()->getListener();
    if (listener) listener->onDiskCreated(getId(), mFlags);
        //检查disk文件系统格式
    readMetadata();
    //读取分区列表
    readPartitions();
    return OK;
}

readPartitions()

status_t Disk::readPartitions() {
    int maxMinors = getMaxMinors();
    if (maxMinors < 0) {
        return -ENOTSUP;
    }

    destroyAllVolumes();

    // Parse partition table

        //......

    if (table == Table::kMbr) {
      if (++it == split.end()) continue;
      int type = 0;
      if (!android::base::ParseInt("0x" + *it, &type)) {
        LOG(WARNING) << "Invalid partition type " << *it;
        continue;
      }
      switch (type) {
        case 0x06:  // FAT16
        case 0x07:  // HPFS/NTFS/exFAT
        case 0x0b:  // W95 FAT32 (LBA)
        case 0x0c:  // W95 FAT32 (LBA)
        case 0x0e:  // W95 FAT16 (LBA)
          //挂载磁盘分区
          createPublicVolume(partDevice);
          break;
      }
    } else if (table == Table::kGpt) {
      if (++it == split.end()) continue;
      auto typeGuid = *it;
      if (++it == split.end()) continue;
      auto partGuid = *it;

      if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) {
        createPublicVolume(partDevice);
      } else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) {
        createPrivateVolume(partDevice, partGuid);
      }
    }
        //......
}

createPublicVolume

void Disk::createPublicVolume(dev_t device) {
    auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
    if (mJustPartitioned) {
        LOG(DEBUG) << "Device just partitioned; silently formatting";
        vol->setSilent(true);
        vol->create();
        vol->format("auto");
        vol->destroy();
        vol->setSilent(false);
    }

    mVolumes.push_back(vol);
    vol->setDiskId(getId());
    //分区初始化
    vol->create();
}

vol->create()

status_t VolumeBase::create() {
    CHECK(!mCreated);

    mCreated = true;
    status_t res = doCreate();

    auto listener = getListener();
    //这里将会回调至frameworks层StorageManagerService中的实现函数,
    if (listener) listener->onVolumeCreated(getId(),
            static_cast<int32_t>(mType), mDiskId, mPartGuid);
        //设置状态
    setState(State::kUnmounted);
    return res;
}

void VolumeBase::setState(State state) {
    mState = state;
    auto listener = getListener();
  //这里将会回调至frameworks层StorageManagerService中的实现函数,当分区初始化完成后,frameworks会发送mount广播。
    if (listener) listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState));
}

以上即是vold进程对于外部存储设备的大致加载过程。监听kennel事件先创建disk,然后再挂载volume。这里需要注意内置的存储没有disk,只有volume。

StorageManagerService

StorageManagerService是由SystemServer来启动的

   /**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored
     * and organized.
     */
    private void startOtherServices() {
        final Context context = mSystemContext;
      
        //......
      
            IStorageManager storageManager = null;
      
        //......
       if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                traceBeginAndSlog("StartStorageManagerService");
                try {
                    /*
                     * NotificationManagerService is dependant on StorageManagerService,
                     * (for media / usb notifications) so we must start StorageManagerService first.
                     */
                    mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
                    //获取binder
                    storageManager = IStorageManager.Stub.asInterface(
                            ServiceManager.getService("mount"));
                } catch (Throwable e) {
                    reportWtf("starting StorageManagerService", e);
                }
                traceEnd();

                traceBeginAndSlog("StartStorageStatsService");
                try {
                    //启动服务
                    mSystemServiceManager.startService(STORAGE_STATS_SERVICE_CLASS);
                } catch (Throwable e) {
                    reportWtf("starting StorageStatsService", e);
                }
                traceEnd();
            }
        }

       //......
    }

StorageManagerService启动

@Override
public void onStart() {
  mStorageManagerService = new StorageManagerService(getContext());
  publishBinderService("mount", mStorageManagerService);
  mStorageManagerService.start();
}

//......

private void start() {
  connect();
}

//......


private void connect() {
  IBinder binder = ServiceManager.getService("storaged");
    
  //......

  binder = ServiceManager.getService("vold");
  if (binder != null) {
    try {
      binder.linkToDeath(new DeathRecipient() {
        @Override
        public void binderDied() {
          Slog.w(TAG, "vold died; reconnecting");
          mVold = null;
          connect();
        }
      }, 0);
    } catch (RemoteException e) {
      binder = null;
    }
  }

  if (binder != null) {
    mVold = IVold.Stub.asInterface(binder);
    try {
      //注入回调至vold进程
      mVold.setListener(mListener);
    } catch (RemoteException e) {
      mVold = null;
      Slog.w(TAG, "vold listener rejected; trying again", e);
    }
  } else {
    Slog.w(TAG, "vold not found; trying again");
  }
}

vold回调

接下来就是最最关键的frameworks层,当存储挂载完成后将由这里发送广播通知到所有监听存储的应用中。例如MediaScanner

  private final IVoldListener mListener = new IVoldListener.Stub() {
    
            //磁盘初始化,这里对应的是vold进程中disk->create()函数
        @Override
        public void onDiskCreated(String diskId, int flags) {
            synchronized (mLock) {
                final String value = SystemProperties.get(StorageManager.PROP_ADOPTABLE);
                switch (value) {
                    case "force_on":
                        flags |= DiskInfo.FLAG_ADOPTABLE;
                        break;
                    case "force_off":
                        flags &= ~DiskInfo.FLAG_ADOPTABLE;
                        break;
                }
                //该集合就是app通过getDisks()函数所获的的集合(有中间封装,但根本还是从这个集合中获取的)
                mDisks.put(diskId, new DiskInfo(diskId, flags));  
            }
        }
    
            //......

        @Override
        public void onDiskMetadataChanged(String diskId, long sizeBytes, String label,
                String sysPath) {
            synchronized (mLock) {
                final DiskInfo disk = mDisks.get(diskId);
                if (disk != null) {
                    disk.size = sizeBytes;
                    disk.label = label;
                    disk.sysPath = sysPath;
                }
            }
        }

        @Override
        public void onDiskDestroyed(String diskId) {
            synchronized (mLock) {
                final DiskInfo disk = mDisks.remove(diskId);
                if (disk != null) {
                    mCallbacks.notifyDiskDestroyed(disk);
                }
            }
        }
                //分区初始化,vol->create()函数
        @Override
        public void onVolumeCreated(String volId, int type, String diskId, String partGuid) {
            synchronized (mLock) {
                final DiskInfo disk = mDisks.get(diskId);
                                //这里没有对disk进行非空判断,经实验,设备内置的存储emulated分区没有disk信息。所以不做非空校验
                final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
                //该集合就是app通过getVolumesList()函数所获的的集合(有中间封装,但根本还是从这个集合中获取的)
                mVolumes.put(volId, vol);
                onVolumeCreatedLocked(vol);
            }
        }

        @Override
        public void onVolumeStateChanged(String volId, int state) {
            synchronized (mLock) {
                final VolumeInfo vol = mVolumes.get(volId);
                if (vol != null) {
                    final int oldState = vol.state;
                    final int newState = state;
                    vol.state = newState;
                    //分区状态改变。
                    onVolumeStateChangedLocked(vol, oldState, newState);
                }
            }
        }

                //......

        @Override
        public void onVolumeDestroyed(String volId) {
            synchronized (mLock) {
                mVolumes.remove(volId);
            }
        }
    };


@GuardedBy("mLock")
private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
  
                //......
  
        mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
  
            //......
  
}


class StorageManagerServiceHandler extends Handler {
  public StorageManagerServiceHandler(Looper looper) {
    super(looper);
  }

  @Override
  public void handleMessage(Message msg) {
         switch (msg.what) {
           
         //......
           
         case H_VOLUME_BROADCAST: {
           final StorageVolume userVol = (StorageVolume) msg.obj;
           final String envState = userVol.getState();
           Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
                  + userVol.getOwner());
                     //根据不同状态获取不同广播,挂载成功后就是mounted广播
           final String action = VolumeInfo.getBroadcastForEnvironment(envState);
           if (action != null) {
             final Intent intent = new Intent(action,
                                              Uri.fromFile(userVol.getPathFile()));
             intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                             | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             mContext.sendBroadcastAsUser(intent, userVol.getOwner());
           }
           break;
         }
            
         //......
  }


小结

目前个人所看到的大致流程就是这样,vold监听kennel上报事件,创建disk,然后再初始化挂载volume,最终发送广播至上层应用。

上一篇 下一篇

猜你喜欢

热点阅读