Android 자원 관리 프레임 워 크 --- 의 자원 정보의 로드 (5)
106122 단어 #AssetManager
안 드 로 이 드 자원 관리 프레임 워 크 --- - 의 안 드 로 이 드 에 있 는 자원 패키지 (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
방법 이다.makeStringBlocks
과 addOverlayPath
방법의 실현 은 우 리 는 각각 안 드 로 이 드 자원 관리 프레임 워 크 인 - 의 안 드 로 이 드 자원 패키지 (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;
}
이것 은 비교적 간단 하 다. 우 리 는
AssetManager
의 addAssetPath
방법의 실현 을 본다.//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;
}
우 리 는 이 방법 이 주로 두 가지 일 을 한 것 을 보 았 다.
path
을 mAssetPaths
에 넣 었 다.대응 하 는 자원 패키지 의 resources. arsc 를 불 러 옵 니 다.그 중에서 후 자 는 path
방법 에서 이 루어 졌 다.우 리 는 이 방법 을 집행 하기 전에 먼저 appendPathToResTable
이 비어 있 는 지 아 닌 지 를 판단 하 는 것 을 알 았 다.mResources
은 mResources
류 의 구성원 으로 그 유형 은 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;
}
}
즉,
AssetManager
의 AssetManager
방법 은 자원 가방 에 있 는 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
에 부여 하 며 mZipSet
을 ResTable
에 추가 한 다음 에 시스템 자원 가방 의 overlay 가방 을 똑 같이 불 러 와 sharedRes
에 추가 합 니 다.그 다음 에 ass
전 체 를 캐 시 에 저장 하면 나중에 시스템 자원 팩 을 불 러 오 면 한 개 sharedRes
씩 추가 하지 않 고 전체 sharedRes
를 함께 추가 하면 됩 니 다. 그리고 우 리 는 sharedRes
이 말 이 시스템 자원 팩 과 그의 overlay 가방 을 함께 ass
에 추가 하 는 것 을 볼 수 있 습 니 다.물론 sharedRes
은 mResources->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) 로 이동 하 십시오.우리 가 여기 서 소개 하 는 것 은 대부분이 안 드 로 이 드 자원 이 관리 하 는 데이터 구조 와 밀접 한 관 계 를 가진다. 만약 에 이런 데이터 구조 에 대해 잘 모 르 면 본 고 를 읽 는 것 이 비교적 힘 들 수 있 기 때문에 앞의 두 편의 글 을 자세히 읽 는 것 을 권장 합 니 다. 이 데이터 구조 에 대해 잘 알 고 있 으 면 본 고 를 읽 는 것 이 훨씬 쉬 울 것 입 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Rails Turbolinks를 페이지 단위로 비활성화하는 방법원래 Turobolinks란? Turbolinks는 링크를 생성하는 요소인 a 요소의 클릭을 후크로 하고, 이동한 페이지를 Ajax에서 가져옵니다. 그 후, 취득 페이지의 데이터가 천이 전의 페이지와 동일한 것이 있...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.