Android 8.1客制化OTG Uディスクのマウントパス名

46997 ワード

Android 8.1客制化OTG Uディスクのマウントパス名
プロジェクトには特殊なUディスクマウントパスや固定されたUディスクマウントパスが必要な場合がありますが、以下の方法で修正できます.
まず、Uディスクのマウントプロセスを見てみましょう.Android 8.1デフォルトのUディスクはstorageディレクトリの下にマウントされていません.また、ファイル管理にもUディスクが表示されません.ファイル管理にUディスクが表示される必要がある場合は、別のブログを参照してください.Android 8.1 OGUディスクはシステムファイル管理の変更を表示できません.
1.Uディスクを挿入すると、まずnewのDiskクラスがあり、そのコンストラクション関数は「eventPath」というパラメータを入力し、ソースファイル:system/vold/Disk.cpp
Disk::Disk(const std::string& eventPath, dev_t device,
        const std::string& nickname, int flags) :
        mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
                false), mJustPartitioned(false) {
    mId = StringPrintf("disk:%u,%u", major(device), minor(device));
    mEventPath = eventPath;		//       eventPath,           mEventPath 

    mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
    mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());
    CreateDeviceNode(mDevPath, mDevice);
}

クラスのプライベート変数「mEventPath」は、「/devices/platform/mt_usb/musb-hdrc.0.auto/usb 1/1-1/1-1.4/...」など、各Uディスクのデバイスパスを保存します.このパスは、USB HUBとUディスクのマウントポートによって異なります.この変数を使用して、自分が必要とするUディスクかどうかを判断できます.
2.次にnew PublicVolumeクラスとVolumeBaseクラスを行い、status_を実行します.t VolumeBase::create()、ソースファイル:system/vold/VolumeBase.cpp
status_t VolumeBase::create() {
    CHECK(!mCreated);
    
    mCreated = true;
    status_t res = doCreate();
    notifyEvent(ResponseCode::VolumeCreated,
            StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
    setState(State::kUnmounted);
    return res;
}

このときの状態は「kUnmounted」です.
3.次にmount操作を実行し、ソースファイル:system/vold/VolumeBase.cpp;system/vold/PublicVolume.cpp
status_t VolumeBase::mount() {
    if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
        LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";
        return -EBUSY;
    }

    setState(State::kChecking);
    status_t res = doMount();
    if (res == OK) {
        setState(State::kMounted);
    } else {
        setState(State::kUnmountable);
    }

    return res;
}

PublicVolumeのdoMount()を呼び出し、mountが成功したかどうかに応じてステータス「kMounted」と「kUnmountable」を設定します.
status_t PublicVolume::doMount() {
    // TODO: expand to support mounting other filesystems
    readMetadata();
    
	......
	
	// Use UUID as stable name, if available
    std::string stableName = getId();			//             ,            
    if (!mFsUuid.empty()) {
        stableName = mFsUuid;
    }
    
    mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());

    mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
    mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
    mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());

    setInternalPath(mRawPath);
    if (getMountFlags() & MountFlags::kVisible) {	//           storage  
        setPath(StringPrintf("/storage/%s", stableName.c_str()));
    } else {
        setPath(mRawPath);
    }

    if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create mount points";
        return -errno;
    }

	......
	
    return OK;
}

Uディスクが1つしかマウントされていない場合は、上のコードの変数「stableName」を自分の名前に直接変更すればいいです.HUBが掛けられ、複数のUディスクがある場合は、下を見続けます.
4.mountは成功または失敗する可能性がありますが、成功するかどうかにかかわらず、Uディスクをアンインストールするときにstatus_を実行します.t VolumeBase::destroy()、これはstatus_t VolumeBase::create()対応、ソースファイル:system/vold/VolumeBase.cpp
status_t VolumeBase::destroy() {
    CHECK(mCreated);

    if (mState == State::kMounted) {
        unmount();
        setState(State::kBadRemoval);
    } else {
        setState(State::kRemoved);
    }

    notifyEvent(ResponseCode::VolumeDestroyed);
    status_t res = doDestroy();
    mCreated = false;
    return res;
}

mountステータスに応じて、「kMounted」であればunmountを実行します.
5.unmountを実行し、ソースファイル:system/vold/VolumeBase.cpp;system/vold/PublicVolume.cpp
status_t VolumeBase::unmount() {
    if (mState != State::kMounted) {
        LOG(WARNING) << getId() << " unmount requires state mounted";
        return -EBUSY;
    }

    setState(State::kEjecting);
    for (const auto& vol : mVolumes) {
        if (vol->destroy()) {
            LOG(WARNING) << getId() << " failed to destroy " << vol->getId()
                    << " stacked above";
        }
    }
    mVolumes.clear();

    status_t res = doUnmount();
    setState(State::kUnmounted);
    return res;
}

PublicVolumeのdoUnmount()を呼び出し、
status_t PublicVolume::doUnmount() {	
    // Unmount the storage before we kill the FUSE process. If we kill
    // the FUSE process first, most file system operations will return
    // ENOTCONN until the unmount completes. This is an exotic and unusual
    // error code and might cause broken behaviour in applications.
    KillProcessesUsingPath(getPath());

    ForceUnmount(kAsecPath);

    ForceUnmount(mFuseDefault);
    ForceUnmount(mFuseRead);
    ForceUnmount(mFuseWrite);
    ForceUnmount(mRawPath);

    if (mFusePid > 0) {
        kill(mFusePid, SIGTERM);
        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
        mFusePid = 0;
    }

    rmdir(mFuseDefault.c_str());
    rmdir(mFuseRead.c_str());
    rmdir(mFuseWrite.c_str());
    rmdir(mRawPath.c_str());

    mFuseDefault.clear();
    mFuseRead.clear();
    mFuseWrite.clear();
    mRawPath.clear();

    return OK;
}

以上が必要な大まかなUディスクマウントフローです.
私の複数のUディスクのカスタムマウントパスを実現する方法は、Uディスクstatus_t PublicVolume::doMount()の場合、Diskクラスのプライベート変数「mEventPath」の値を取得し、特殊名称が必要なUディスクであるか否かを判断し、特殊名称が必要なUディスクであれば、統一名称接頭辞+数字番号、例えば「USB 1~USB 10」を使用して、合計10個のUディスクに特殊名称を使用することをサポートし、mountが必要なたびに名前番号を割り当て、グローバル変数配列(自己定義)を使用して、対応する番号が割り当てられているかどうかをマークします.割り当てられた番号は、mountが成功したり、失敗したりする可能性があります.status_t VolumeBase::destroy()で割り当てられた番号のタグをクリアします.
参照コードは次のとおりです.
status_t PublicVolume::doMount() {
    // TODO: expand to support mounting other filesystems
    readMetadata();

	......

	#if 0	//      
	// Use UUID as stable name, if available
    std::string stableName = getId();
    if (!mFsUuid.empty()) {
        stableName = mFsUuid;
    }
	#endif
	
	/***************************************************************************/
	std::string stableName = getId();
	unsigned char i;
	const char *Path = getEventPath().data();//    Disk     mEventPath   ,      
	//       ,  USB         HUB,     HUB     ,         1   
	//             ,        , kernel   sysfs  device  ,       
	if( strncmp(Path,"/devices/platform/mt_usb/musb-hdrc.0.auto/usb1/1-1/1-1.1",strlen("/devices/platform/mt_usb/musb-hdrc.0.auto/usb1/1-1/1-1.*")) >= 0 )
	{
		//                 
		for(i = 0; i < 10; i++)
		{
			//flag   0,      
			if(MountPointFlag[i] == 0)		//                  ,            
				break;
		}
		
		if(i < 10)
		{
			stableName = StringPrintf("USB%d", (i + 1));
			MountPointFlag[i] = 1;		// 1,      
		}
	}
	/***************************************************************************/
	
	//    U     ,    /mnt/media_rw ,    /storage 
    mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());

    mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
    mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
    mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());

    setInternalPath(mRawPath);
    if (getMountFlags() & MountFlags::kVisible) {	//             
        setPath(StringPrintf("/storage/%s", stableName.c_str()));
    } else {
        setPath(mRawPath);
    }
    //          setPath(),           VolumeBase      “mPath” 

    if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
        PLOG(ERROR) << getId() << " failed to create mount points";
        return -errno;
    }

	......

    return OK;
}
status_t VolumeBase::destroy() {
    CHECK(mCreated);

	/***************************************************************************/
	const std::string Path = getPath();// VolumeBase      “mPath”            
	//     U    storage,    storage    
	if( strncmp(Path.data(),"/storage/USB",strlen("/storage/USB")) == 0 )
	{
		//         
		unsigned char clear = (unsigned char)atoi(Path.substr(strlen("/storage/USB")).c_str());
		//                  ,         
		if(pMountPointFlag!= NULL)
		{
			if( (clear > 0) && (clear <= 10) )
				pMountPointFlag[clear - 1] = 0;		// 0,       
		}
	}
	/***************************************************************************/

    if (mState == State::kMounted) {
        unmount();
        setState(State::kBadRemoval);
    } else {
        setState(State::kRemoved);
    }

    notifyEvent(ResponseCode::VolumeDestroyed);
    status_t res = doDestroy();
    mCreated = false;
    return res;
}

以上が修正方法と参考コードです!
いくつかの注意:1.SDカードリーダーが差し込むとnew Diskクラスになりますが、mountは実行されません.私は最初はDiskのコンストラクション関数で「mEventPath」の値を直接判断し、割り当てられた名前番号で、SDカードリーダーが1つの番号を占有し、解放されないので、mountが必要なときに割り当てます.同様に、もう1つの場合もstatus_が実行されているt VolumeBase::create()ですが、mountはありません.2.status_t VolumeBase::destroy()では、status_ではなく、割り当てられた番号を解放します.t PublicVolume::doUnmount()では、mountが成功しなければunmountは実行されないため、番号が解放されません.3.時々現れ、プロセスはstatusを実行した.t VolumeBase::create()は、次に2回mountを実行します.例えば、空のSDカードリーダーを挿入した後、破損したSDカードを挿入すると、mount関数で判断しなければなりません.同じプロセスで、最初のmountはすでに番号を割り当てて、mountに行って、前に割り当てた番号を使って、新しい割り当てに行かないでください.そうしないとdestroy()のとき、最後のmount割り当てをクリアするだけです.前のリリースはできません!