Android 자원 관리 프레임 워 크 --- 의 자원 정보의 로드 (5)

106122 단어 #AssetManager
안 드 로 이 드 자원 관리 프레임 워 크 - - 의 안 드 로 이 드 에서 자원 패키지 (2) 라 는 글 에서 우 리 는 안 드 로 이 드 가 자원 패키지 에 대한 관 리 를 말 했다. 물론 이 관 리 는 우리 가 비교적 거시적 으로 말한다.안 드 로 이 드 자원 관리 와 관련 된 데이터 구 조 를 알 게 된 후에 우 리 는 안 드 로 이 드 가 자원 팩 에 대한 관리 와 조직 을 깊이 있 게 배 울 수 있 습 니 다. 이 편 에서 우 리 는 자원 정보의 로드 를 먼저 말 할 수 있 습 니 다.
        안 드 로 이 드 자원 관리 프레임 워 크 --- - 의 안 드 로 이 드 에 있 는 자원 패키지 (2) 에 서 는 응용 프로그램 이 시 작 된 후에 framework 는 ResourcesManager.getTopLevelResources() 방법 으로 AssetManager 대상 을 만 들 고 AssetManager 관련 방법 을 호출 하여 이 응용 자체 (자신 도 자원 패키지), 자원 공유 라 이브 러 리, overlay 패 키 지 를 모두 추가 합 니 다.구체 적 으로 어떻게 이 루어 졌 을까요?우 리 는 이어서 아래 를 내 려 다 보 았 다.
    //framework/base/core/java/android/content/res/AssetManager.java
    
    public final int addAssetPath(String path) {
        synchronized (this) {
            //     ,res cookie ,        AssetManager           +1
            int res = addAssetPathNative(path);
            //        Global(Value) String Pool
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }

    public final int addOverlayPath(String idmapPath) {
        synchronized (this) {

            //     ,res cookie ,        AssetManager           +1
            int res = addOverlayPathNative(idmapPath);
            //        Global(Value) String Pool
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }

        그 중에서 응용 자체 와 자원 공유 라 이브 러 리 를 추가 하 는 것 은 addAssetPath 방법 이 고 overlay 패 키 지 를 추가 하 는 것 은 addOverlayPath 방법 이다.makeStringBlocksaddOverlayPath 방법의 실현 은 우 리 는 각각 안 드 로 이 드 자원 관리 프레임 워 크 인 - 의 안 드 로 이 드 자원 패키지 (2) 와 안 드 로 이 드 자원 관리 중의 Runtime Resources Overlay - - 의 overlay 패키지 의 로드 (4) 에서 이미 말 했 으 며, 여 기 는 더 이상 군말 하지 않 습 니 다.우리 가 보기에 addAssetPathNative 방법 은 그것 에 대응 하 는 native 실현 은:
//frameworks/base/core/jni/android_util_AssetManager.cpp
static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
                                                       jstring path)
{
    //    
    ScopedUtfChars path8(env, path);
    if (path8.c_str() == NULL) {
        return 0;
    }
    //  native  AssetManager     ,         java       ,        
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return 0;
    }

    int32_t cookie;
    //   ,cookie     
    bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
    //       cookie ,    0
    return (res) ? static_cast<jint>(cookie) : 0;
}

        이것 은 비교적 간단 하 다. 우 리 는 AssetManageraddAssetPath 방법의 실현 을 본다.
//frameworks/base/libs/androidfw/AssetManager.cpp
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
{
    //       ,  
    
    ......
    
    //              
    for (size_t i=0; i<mAssetPaths.size(); i++) {
        if (mAssetPaths[i].path == ap.path) {
            if (cookie) {
                //cookie        + 1
                *cookie = static_cast<int32_t>(i+1);
            }
            return true;
        }
    }

    //          AndroidManifest.xml,     ,   false

    ......

    //          
    mAssetPaths.add(ap);
    if (cookie) {
        //cookie        + 1
        *cookie = static_cast<int32_t>(mAssetPaths.size());
    }

   #ifdef HAVE_ANDROID_OS
    //          overlay package
    asset_path oap;
    for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
        mAssetPaths.add(oap);
    }
   #endif

    //      ,     resources.arsc        
    if (mResources != NULL) {
        appendPathToResTable(ap);
    }

    return true;
}

        우 리 는 이 방법 이 주로 두 가지 일 을 한 것 을 보 았 다. pathmAssetPaths 에 넣 었 다.대응 하 는 자원 패키지 의 resources. arsc 를 불 러 옵 니 다.그 중에서 후 자 는 path 방법 에서 이 루어 졌 다.우 리 는 이 방법 을 집행 하기 전에 먼저 appendPathToResTable 이 비어 있 는 지 아 닌 지 를 판단 하 는 것 을 알 았 다.mResourcesmResources 류 의 구성원 으로 그 유형 은 AssetManager 이 고 구조 ResTable 대상 을 구성 할 때 이 구성원 에 게 값 을 부여 하지 않 는 다. 즉, AssetManager 대상 이 구조 되 자마자 addAssetPath 방법 으로 자원 패 키 지 를 추가 하면 자원 패 키 지 는 로드 되 지 않 는 다 는 것 이다.그럼 이 상황 에서 도대체 언제 불 러 올 까요?
//frameworks/base/libs/androidfw/AssetManager.cpp
const ResTable* AssetManager::getResTable(bool required) const
{
    //       ,   
    ResTable* rt = mResources;
    if (rt) {
        return rt;
    }

    mResources = new ResTable();
    //     Locale  ,        
    updateResourceParamsLocked();

    bool onlyEmptyResources = true;
    const size_t N = mAssetPaths.size();
    //     mAssetPaths         resources.arsc
    for (size_t i=0; i<N; i++) {
        bool empty = appendPathToResTable(mAssetPaths.itemAt(i));
        onlyEmptyResources = onlyEmptyResources && empty;
    }
    //required   true,    false   ,      mAssetPaths 
    //         resources.arsc,    mResources
    if (required && onlyEmptyResources) {
        ALOGW("Unable to find resources file resources.arsc");
        delete mResources;
        mResources = NULL;
    }
}

        즉, AssetManagerAssetManager 방법 은 자원 가방 에 있 는 resources. arsc 를 즉시 불 러 오 는 것 이 아니 라 구조 addAssetPath 구성원, 즉 mResources 인 스 턴 스 를 불 러 올 때 불 러 오 는 지연 이 있 을 수 있다.그럼 이 getResTable 방법 은 구체 적 으로 언제 호출 되 나 요?우리 가 ResTable 에서 자원 id, 자원 항목, 자원 로드, StringBlock 등 을 찾 을 때 이 방법 을 사용 하여 resources. arsc 를 불 러 옵 니 다.
        다음은 AssetManager resources. arsc 를 어떻게 불 러 오 는 지 보 겠 습 니 다.
//frameworks/base/libs/androidfw/AssetManager.cpp
bool AssetManager::appendPathToResTable(const asset_path& ap) const {
    /*
     *    ass          resources.arsc,
     * sharedRes           resources.arsc      
     *     ResTable           ,  ResTable       Asset   
     */
    Asset* ass = NULL;
    ResTable* sharedRes = NULL;
    
    bool shared = true;
    bool onlyEmptyResources = true;
    MY_TRACE_BEGIN(ap.path.string());
    //idmap  RRO     ,      
    Asset* idmap = openIdmapLocked(ap);
    /*
     *                    ,
     *        ,                 framework-res.apk
     *    Android      
     */
    size_t nextEntryIdx = mResources->getTableCount();

    /*
     *      resources.arsc,                 apk 
     *       if  
     *  AssetManager          resources.arsc 
     *          else  
     */
     //resources.arsc apk 
    if (ap.type != kFileTypeDirectory) {
        
        if (nextEntryIdx == 0) {//    framework-res.apk,   Google Android     
            //              overlay        ,     ,     
            //ResTable  ,   ,   sharedRes         
            sharedRes = const_cast<AssetManager*>(this)->
                mZipSet.getZipResourceTable(ap.path);
            if (sharedRes != NULL) {
                /**
                 *         ,           ,         
                 *                     AssetManager  Resources     ,
                 *   AssetManager          ,           
                 */ 
                nextEntryIdx = sharedRes->getTableCount();
            }
        }

        //                     ,         ,   
        if (sharedRes == NULL) {
            //   ,            Asset  
            ass = const_cast<AssetManager*>(this)->
                mZipSet.getZipResourceTableAsset(ap.path);
            //      ,    ,   resources.arsc,     ass    
            if (ass == NULL) {
                ALOGV("loading resource table %s
"
, ap.path.string()); // resources.arsc ass = const_cast<AssetManager*>(this)-> openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); // if (ass != NULL && ass != kExcludedAsset) { ass = const_cast<AssetManager*>(this)-> mZipSet.setZipResourceTableAsset(ap.path, ass); } } // , , overlay package if (nextEntryIdx == 0 && ass != NULL) { // If this is the first resource table in the asset // manager, then we are going to cache it so that we // can quickly copy it out for others. ALOGV("Creating shared resources for %s", ap.path.string()); // ResTable sharedRes = new ResTable(); // resources.arsc idmap sharedRes->add(ass, idmap, nextEntryIdx + 1, false); #ifdef HAVE_ANDROID_OS const char* data = getenv("ANDROID_DATA"); LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set"); String8 overlaysListPath(data); overlaysListPath.appendPath(kResourceCache); overlaysListPath.appendPath("overlays.list"); // overlay package, sharedRes, addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx); #endif // sharedRes sharedRes = const_cast<AssetManager*>(this)-> mZipSet.setZipResourceTable(ap.path, sharedRes); } } } else {//resources.arsc apk , // , Asset ass = const_cast<AssetManager*>(this)-> openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); // apk , , shared = false; } if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) { if (sharedRes != NULL) { ALOGV("Copying existing resources for %s", ap.path.string()); // , overlay package //mResources mResources->add(sharedRes); } else { ALOGV("Parsing resources for %s", ap.path.string()); // ( resources.arsc idmap ) mResources->add(ass, idmap, nextEntryIdx + 1, !shared); } onlyEmptyResources = false; // , if (!shared) { delete ass; } } else { // ALOGV("Installing empty resources in to table %p
"
, mResources); mResources->addEmpty(nextEntryIdx + 1); } if (idmap != NULL) { delete idmap; } MY_TRACE_END(); return onlyEmptyResources; }

         appendPathToResTable 방법 은 요약 해도 간단 하 다. 바로 캐 시, 로 딩 자원 (이 중간 에 생 성 가능 appendPathToResTable, Asset 등 대상), 캐 시, 이상 상황 처리 (자원 을 찾 지 못 했 을 때) 이다.그러나 이와 관련 된 상황 이 비교적 많 기 때문에 Zygote 가 일어 난 후에 preload 시스템 자원, 로 딩 시스템 자원 을 응용 하고 첫 번 째 로 다른 자원 을 불 러 오 는 것 (응용 자체, 자원 공유 라 이브 러 리, overlay package 포함), 두 번 째 로 다른 자원 을 불 러 오 는 것 등 네 가지 상황 을 포함한다.
        Zygote 가 일어나 면 preload 라 는 상황 부터Zygote 프로 세 스에 서 VM 을 불 러 오고 자바 세계 에 들 어가 면 ZygoteInit. java 의 main 방법 을 실행 할 수 있다 는 것 을 알 고 있 습 니 다.이것 은 server Socket 을 만 들 것 입 니 다. SystemServier 프로 세 스 가 보 낸 안 드 로 이 드 애플 리 케 이 션 생 성 요청 에 응답 한 다음 에 우리 가 자주 사용 하 는 클래스 와 안 드 로 이 드 시스템 자원 을 포함 하여 많은 것 을 미리 불 러 옵 니 다.이렇게 하면 Android 응용 프로 세 스 가 Zygote 프로 세 스 fork 에서 나 온 후에 다시 불 러 오지 않 아 도 되 고 응용 프로그램의 시작 시간 을 절약 할 수 있 습 니 다.이 럴 때 시스템 AssetManager 를 만 듭 니 다. 이때 ResTable 방법 은 다음 과 같 습 니 다.
                 appendPathToResTable 캐 시 에서 가 져 오기 nextEntryIdx = 0, 결 과 는 mZipSet, 그리고 sharedRes 캐 시 에서 가 져 오기 NULL, 결 과 는 mZipSet, 그리고 시스템 자원 패키지 에 있 는 resources. arsc 파일 을 호출 하여 ass 에 값 을 부여 하고 이 NULL 캐 시 에 저장 openNonAssetInPathLocked 하면 캐 시 에서 가 져 올 수 있 습 니 다.그 다음 에 ass 대상 을 만 들 고 ass 에 부여 하 며 mZipSetResTable 에 추가 한 다음 에 시스템 자원 가방 의 overlay 가방 을 똑 같이 불 러 와 sharedRes 에 추가 합 니 다.그 다음 에 ass 전 체 를 캐 시 에 저장 하면 나중에 시스템 자원 팩 을 불 러 오 면 한 개 sharedRes 씩 추가 하지 않 고 전체 sharedRes 를 함께 추가 하면 됩 니 다. 그리고 우 리 는 sharedRes 이 말 이 시스템 자원 팩 과 그의 overlay 가방 을 함께 ass 에 추가 하 는 것 을 볼 수 있 습 니 다.물론 sharedResmResources->add(sharedRes); 의 실례 이자 mResources 에서 가장 중요 한 구성원 으로 자원 을 모두 그 안에 불 러 왔 다.이렇게 하면 이 시스템 의 mResources 자원 을 다 불 러 옵 니 다.물론 overlay package 가 어떻게 ResTable 에 추가 되 었 는 지 한 마디 로 가 져 왔 습 니 다. 안 드 로 이 드 자원 관리 중의 Runtime Resources Overlay - - 의 overlay 패키지 의 로드 (4) 를 참고 하 십시오.
        그리고 시스템 자원 을 불 러 오 는 상황 을 응용 하면 우 리 는 앞에서 모든 안 드 로 이 드 응용 프로그램 Assetmanager 에서 시스템 의 자원 정 보 를 불 러 올 것 이 라 고 말 한 적 이 있다. 구체 적 으로 어떻게 불 러 오 는 지 는 안 드 로 이 드 자원 관리 프레임 워 크 - - 의 안 드 로 이 드 중의 자원 팩 (2) 을 참조 하 자.로드 할 때 AssetManager 방법의 절 차 는:
                 sharedRes 캐 시 에서 가 져 온 AssetManager 결 과 는 appendPathToResTable 이 아니 라 수정 nextEntryIdx = 0, mZipSet 이렇게 하면 시스템 자원 팩 이 모두 sharedRes 에 추 가 됩 니 다.
        우 리 는 응용 프로그램 이 처음으로 다른 자원 (응용 자체, 자원 공유 라 이브 러 리, overlay package 포함) 을 불 러 오 는 상황 을 다시 봅 니 다. NULL 은 0 이 아 닙 니 다. 이 때 시스템 자원 패키지 와 overlay 패 키 지 를 추 가 했 기 때 문 입 니 다. nextEntryIdx = sharedRes->getTableCount(); 은 비어 있 고 캐 시 에서 찾기 mResources->add(sharedRes); 는 비어 있 습 니 다. mResources 방법 으로 자원 패키지 에 있 는 resources. arsc 파일 을 열 고 값 을 부여 합 니 다 nextEntryIdx = mResources->getTableCount();.이 sharedRes 캐 시 에 저장 하면 캐 시 에서 가 져 올 수 있 습 니 다.이때 ass 가 비어 있 지 않 고 호출 openNonAssetInPathLocked 을 통 해 자원 패키지 의 로드 를 완성 합 니 다.
        마지막 으로 두 번 째 로 다른 자원 (응용 자체, 자원 공유 라 이브 러 리, overlay package 포함) 을 불 러 오 는 상황 을 봅 니 다. ass 은 0 이 아 닙 니 다. 이 때 시스템 자원 패키지 와 overlay 패 키 지 를 추 가 했 기 때 문 입 니 다. ass 은 비어 있 고 캐 시 에서 찾기 mZipSet 는 비어 있 지 않 습 니 다. 호출 ass 을 통 해 자원 패키지 의 로드 를 완 료 했 습 니 다.
        여기까지 mResources->add(ass, idmap, nextEntryIdx + 1, !shared);nextEntryIdx = mResources->getTableCount(); 방법 은 마침내 끝났다. 이 방법 에서 가장 관건 적 인 단 계 는 sharedRes 류 의 대상 ass 을 호출 하 는 mResources->add(ass, idmap, nextEntryIdx + 1, !shared); 방법 이다.add 방법 은 여러 개 를 다시 실 었 지만 결국 두 가지 방법 중 하나 로 갈 것 입 니 다.
//frameworks/base/libs/androidfw/ResourceTypes.cpp
status_t ResTable::add(ResTable* src)
{
    mError = src->mError;
    //  Headers
    for (size_t i=0; i<src->mHeaders.size(); i++) {
        mHeaders.add(src->mHeaders[i]);
    }
    //  PackageGroups
    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
        PackageGroup* srcPg = src->mPackageGroups[i];
        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
        //   PackageGroup,  package
        //      overlay package     target package      PackageGroup 
        for (size_t j=0; j<srcPg->packages.size(); j++) {
            pg->packages.add(srcPg->packages[j]);
        }
        ///   PackageGroup  TypeList
        for (size_t j = 0; j < srcPg->types.size(); j++) {
            if (srcPg->types[j].isEmpty()) {
                continue;
            }

            TypeList& typeList = pg->types.editItemAt(j);
            typeList.appendVector(srcPg->types[j]);
        }
        //  DynamicRefTable
        pg->dynamicRefTable.addMappings(srcPg->dynamicRefTable);
        pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
        mPackageGroups.add(pg);
    }
    //
    memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));

    return mError;
}

        이 방법 은 매우 간단 하 다. 바로 각 AssetManager 중의 데이터 구 조 를 추가 하 는 것 이다.DynamicRefTable 은 자원 공유 라 이브 러 리 와 관련 된 것 입 니 다. 안 드 로 이 드 자원 관리 중의 Shared Library 와 Dynamic Reference - --- 의 AssetManager 처리 (4) 를 참조 하 십시오.다음은 다른 방법 을 살 펴 보 자.
//frameworks/base/libs/androidfw/ResourceTypes.cpp

/*
 * data    resources.arsc Asset     ,  resources.arsc     
 * dataSize data   
 * idmapData    idmap   Asset     ,  idmap     
 * idmapDataSize idmapData   
 * cookie      index + 1
 * copyData    data  ResTable ,  appendPathToResTable   shared
 *  false copyData true,   false
 */
status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, 
            size_t idmapDataSize, const int32_t cookie, bool copyData)
{
    //......    ,     

    //  Header    resources.arsc,        
    Header* header = new Header(this);
    //mHeaders             resources.arsc    
    header->index = mHeaders.size();
    //cookie = mHeaders.size() + 1
    header->cookie = cookie;
    // idmap      ,header       
    if (idmapData != NULL) {
        header->resourceIDMap = (uint32_t*) malloc(idmapDataSize);
        if (header->resourceIDMap == NULL) {
            delete header;
            return (mError = NO_MEMORY);
        }
        memcpy(header->resourceIDMap, idmapData, idmapDataSize);
        header->resourceIDMapSize = idmapDataSize;
    }
    //mHeaders    ResTable(   AssetManager         )
    mHeaders.add(header);
    
    //......      ,        resources.arsc   

    //resources.arsc           header
    header->header = (const ResTable_header*)data;
    header->size = dtohl(header->header->header.size);
    //dataEnd,        resources.arsc   
    header->dataEnd = ((const uint8_t*)header->header) + header->size;

    size_t curPackage = 0;
    /**
    *  resources.arsc    header
    *           header
    *        resources.arsc     header,    
    *     ,    
    *  ,resources.arsc            :
    *RES_STRING_POOL_TYPE   global string pool
    *RES_TABLE_PACKAGE_TYPE      
    */
    const ResChunk_header* chunk =
        (const ResChunk_header*)(((const uint8_t*)header->header)
                                 + dtohs(header->header->header.headerSize));
    //          
    while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
           ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
        //                 
        const size_t csize = dtohl(chunk->size);
        const uint16_t ctype = dtohs(chunk->type);
        if (ctype == RES_STRING_POOL_TYPE) {
            // global string pool
            if (header->values.getError() != NO_ERROR) {
                // global string pool    
                status_t err = header->values.setTo(chunk, csize);
                if (err != NO_ERROR) {
                    return (mError=err);
                }
            } else {
                ALOGW("Multiple string chunks found in resource table.");
            }
        } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
            //     
            if (curPackage >= dtohl(header->header->packageCount)) {
                ALOGW("More package chunks were found than the %d declared in the header.",
                     dtohl(header->header->packageCount));
                return (mError=BAD_TYPE);
            }
            //        parsePackage  
            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
                return mError;
            }
            curPackage++;
       } else {
           ALOGW("Unknown chunk type 0x%x in table at %p.
"
, ctype, (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))); } // chunk = (const ResChunk_header*) (((const uint8_t*)chunk) + csize); } // , if (curPackage < dtohl(header->header->packageCount)) { // ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", (int)curPackage, dtohl(header->header->packageCount)); return (mError=BAD_TYPE); } mError = header->values.getError(); if (mError != NO_ERROR) { // global string pool ALOGW("No string values found in resource table!"); } TABLE_NOISY(ALOGV("Returning from add with mError=%d
"
, mError)); return mError; }

        이 방법 은 resources. arsc 의 2 급 chunk 를 분석 한 다음 에 Restable:: Header 형식 으로 기록 하고 Restable 의 mHeaders 에 추가 하 는 것 입 니 다.우 리 는 다음 에 parsePackage 방법 을 보 겠 습 니 다. 이 방법 은 비교적 길 고 본 논문 과 관계 가 크 지 않 은 내용 은 여기에 붙 이지 않 습 니 다.
//frameworks/base/libs/androidfw/ResourceTypes.cpp
status_t ResTable::parsePackage(const ResTable_package* const pkg,
                                const Header* const header)
{
     const uint8_t* base = (const uint8_t*)pkg;
     const uint32_t pkgSize = dtohl(pkg->header.size);
     //       resources.arsc    id
     uint32_t id = dtohl(pkg->id);
     
     //idmap     ,       ,  ......
     
     PackageGroup* group = NULL;
     Package* package = new Package(this, header, pkg);
     /**
     *  type string pool,           
     *  ResStringPool        ,         
     */
     err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
                                   header->dataEnd-(base+dtohl(pkg->typeStrings)));
     /**
     *  type string pool,           
     *  ResStringPool        ,         
     */
     err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
                                  header->dataEnd-(base+dtohl(pkg->keyStrings)));
     //mPackageMap  -1   id       PackageGroup mPackageGroups    
     //      ,  id   target Package id         target pacakge    
     size_t idx = mPackageMap[id];
     if (idx == 0) { 
         //idx = 0,           ,       idx   index + 1
         idx = mPackageGroups.size() + 1;
         //    
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
         /**
          *   PackageGroup  ,     overlay package    ,
          *      ,      PackageGroup
          */
         group = new PackageGroup(this, String16(tmpName), id);
         if (group == NULL) {
            delete package;
            return (mError=NO_MEMORY);
        }
        //    
        err = mPackageGroups.add(group);
        if (err < NO_ERROR) {
            return (mError=err);
        }
        //          ,        
        size_t N = mPackageGroups.size();
        for (size_t i = 0; i < N; i++) {
            // ResTable    PackageGroup,        id,
            //               
            mPackageGroups[i]->dynamicRefTable.addMapping(
                    group->name, static_cast<uint8_t>(group->id));
        }
     } else {
         //     ,   overlay package,        ,  ......
         //        AssetManager   ,     id    ,
         //       ,     typeId  ,   。
     }
     // new   package   group 
     err = group->packages.add(package);

     //  package header
     const ResChunk_header* chunk =
        (const ResChunk_header*)(((const uint8_t*)pkg)
                                 + dtohs(pkg->header.headerSize));
     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
     /**
     *  resources.arsc package        
     *        (type stringpool、keystring pool  ,            ):
     *RES_TABLE_TYPE_SPEC_TYPE
     *RES_TABLE_TYPE_TYPE
     *RES_TABLE_LIBRARY_TYPE
     */
     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
           ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
         //           
         const size_t csize = dtohl(chunk->size);
         const uint16_t ctype = dtohs(chunk->type);
         //  TYPE_SPEC   
         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
             const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
             //        entryCount
             const size_t typeSpecSize = dtohl(typeSpec->header.size);
             const size_t newEntryCount = dtohl(typeSpec->entryCount);
             // entry  
             if (newEntryCount > 0) {
                 //type   1     ,    - 1
                 uint8_t typeIndex = typeSpec->id - 1;
                 
                 //idmap     ,  ......

                 //  typeIndex    typeList,   overlay package    ,   typeList     
                 TypeList& typeList = group->types.editItemAt(typeIndex);
                 if (!typeList.isEmpty()) {
                     //target  Type
                     const Type* existingType = typeList[0];
                     /**
                     *  if        :   AssetManager     id    
                     */
                     if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
                         ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
                             (int) newEntryCount, (int) existingType->entryCount);
                         // We should normally abort here, but some legacy apps declare
                         // resources in the 'android' package (old bug in AAPT).
                     }
                 }
                 //  type       
                 Type* t = new Type(header, package, newEntryCount);
                 t->typeSpec = typeSpec;
                 t->typeSpecFlags = (const uint32_t*)(
                    ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
                 
                 //idmap     ,  ......
                 
                 //   target pakage   typeList  
                 typeList.add(t);
             }
         } else if (ctype == RES_TABLE_TYPE_TYPE) {
             const ResTable_type* type = (const ResTable_type*)(chunk);
             //        entryCount
             const uint32_t typeSize = dtohl(type->header.size);
             const size_t newEntryCount = dtohl(type->entryCount);
             //   entry
             if (newEntryCount > 0) {
                // type   
                uint8_t typeIndex = type->id - 1;
                                 
                 //idmap     ,  ......
                 
                //           Type  
                Type* t = typeList.editItemAt(typeList.size() - 1);
                //             
                t->configs.add(type);
             }
         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
             //          ,       ,    :
             //https://blog.csdn.net/dayong198866/article/details/95226237
         } else {
                 //......
         }
         chunk = (const ResChunk_header*)
            (((const uint8_t*)chunk) + csize);
     }
     return NO_ERROR;
}

        이 방법 은 전 달 된 resources. arsc 의 RES 에 따 른 것 입 니 다.TABLE_PACKAGE_TYPE 형식의 chunk, 생 성 appendPathToResTable, ResTable, mResources, add 등 대상 을 만 들 고 이 chunk 의 데이터 주 소 를 만 든 데이터 구조 에 기록 하여 resources. arsc 에 대한 분석 을 완료 합 니 다.그 후에 우 리 는 이런 데이터 구 조 를 통 해 자원 에 대한 관 리 를 할 수 있다.또한 본 문 력 은 간결 을 추구 하고 RRO 와 idmap 와 관련 된 처 리 를 생략 하 였 습 니 다. 이 부분 에 관심 이 있다 면 Android 자원 관리 중의 Runtime Resources Overlay - - 의 overlay 패키지 의 로드 (4) 로 이동 하 십시오.
        우리 가 여기 서 소개 하 는 것 은 대부분이 안 드 로 이 드 자원 이 관리 하 는 데이터 구조 와 밀접 한 관 계 를 가진다. 만약 에 이런 데이터 구조 에 대해 잘 모 르 면 본 고 를 읽 는 것 이 비교적 힘 들 수 있 기 때문에 앞의 두 편의 글 을 자세히 읽 는 것 을 권장 합 니 다. 이 데이터 구조 에 대해 잘 알 고 있 으 면 본 고 를 읽 는 것 이 훨씬 쉬 울 것 입 니 다.

좋은 웹페이지 즐겨찾기