frameworks/base/core/java/android/content/res/Resources.java public CharSequence getText(int id) throws NotFoundException { CharSequence res = mAssets.getResourceText(id); if (res != null) { return res; } throw new NotFoundException("String resource ID #0x" + Integer.toHexString(id)); } frameworks/base/core/java/android/content/res/AssetManager.java /*package*/ final CharSequence getResourceText(int ident) { synchronized (this) { TypedValue tmpValue = mValue; int block = loadResourceValue(ident, (short) 0, tmpValue, true);//进这里看看 if (block >= 0) { if (tmpValue.type == TypedValue.TYPE_STRING) { return mStringBlocks[block].get(tmpValue.data); } return tmpValue.coerceToString(); } } return null; } frameworks/base/core/jni/android_util_AssetManager.cpp static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz, jint ident, jshort density, jobject outValue, jboolean resolve) { AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { return 0; } const ResTable& res(am->getResources()); Res_value value; ResTable_config config; uint32_t typeSpecFlags; ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);在这里获取到了值 #if THROW_ON_BAD_ID if (block == BAD_INDEX) { jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); return 0; } #endif uint32_t ref = ident; if (resolve) { block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config); #if THROW_ON_BAD_ID if (block == BAD_INDEX) { jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); return 0; } #endif } return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block; } frameworks/base/libs/androidfw/ResourceTypes.cpp ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density, uint32_t* outSpecFlags, ResTable_config* outConfig) const { if (mError != NO_ERROR) { return mError; } const ssize_t p = getResourcePackageIndex(resID); const int t = Res_GETTYPE(resID); const int e = Res_GETENTRY(resID); if (p < 0) { if (Res_GETPACKAGE(resID)+1 == 0) { ALOGW("No package identifier when getting value for resource number 0x%08x", resID); } else { ALOGW("No known package when getting value for resource number 0x%08x", resID); } return BAD_INDEX; } if (t < 0) { ALOGW("No type identifier when getting value for resource number 0x%08x", resID); return BAD_INDEX; } const Res_value* bestValue = NULL; const Package* bestPackage = NULL; ResTable_config bestItem; memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up if (outSpecFlags != NULL) *outSpecFlags = 0; // Look through all resource packages, starting with the most // recently added. const PackageGroup* const grp = mPackageGroups[p]; if (grp == NULL) { ALOGW("Bad identifier when getting value for resource number 0x%08x", resID); return BAD_INDEX; } // Allow overriding density const ResTable_config* desiredConfig = &mParams; ResTable_config* overrideConfig = NULL; if (density > 0) { overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config)); if (overrideConfig == NULL) { ALOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno)); return BAD_INDEX; } memcpy(overrideConfig, &mParams, sizeof(ResTable_config)); overrideConfig->density = density; desiredConfig = overrideConfig; }else{ overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config)); if (overrideConfig == NULL) { ALOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno)); return BAD_INDEX; } memcpy(overrideConfig, &mParams, sizeof(ResTable_config)); overrideConfig->smallestScreenWidthDp = 720; desiredConfig = overrideConfig; }//修改,作测试用. ssize_t rc = BAD_VALUE; size_t ip = grp->packages.size(); while (ip > 0) { ip--; int T = t; int E = e; const Package* const package = grp->packages[ip]; if (package->header->resourceIDMap) { uint32_t overlayResID = 0x0; status_t retval = idmapLookup(package->header->resourceIDMap, package->header->resourceIDMapSize, resID, &overlayResID); if (retval == NO_ERROR && overlayResID != 0x0) { // for this loop iteration, this is the type and entry we really want ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID); T = Res_GETTYPE(overlayResID); E = Res_GETENTRY(overlayResID); } else { // resource not present in overlay package, continue with the next package continue; } } const ResTable_type* type; const ResTable_entry* entry; const Type* typeClass; ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);//最终会进入getEntry,里面作了很多对当前Config的比较处理。 if (offset <= 0) { // No {entry, appropriate config} pair found in package. If this // package is an overlay package (ip != 0), this simply means the // overlay package did not specify a default. // Non-overlay packages are still required to provide a default. if (offset < 0 && ip == 0) { ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n", resID, T, E, ip, (int)offset); rc = offset; goto out; } continue; } if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) { if (!mayBeBag) { ALOGW("Requesting resource %p failed because it is complex\n", (void*)resID); } continue; } TABLE_NOISY(aout << "Resource type data: " << HexDump(type, dtohl(type->header.size)) << endl); if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) { ALOGW("ResTable_item at %d is beyond type chunk data %d", (int)offset, dtohl(type->header.size)); rc = BAD_TYPE; goto out; } const Res_value* item = (const Res_value*)(((const uint8_t*)type) + offset); ResTable_config thisConfig; thisConfig.copyFromDtoH(type->config); if (outSpecFlags != NULL) { if (typeClass->typeSpecFlags != NULL) { *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]); } else { *outSpecFlags = -1; } } if (bestPackage != NULL && (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) { // Discard thisConfig not only if bestItem is more specific, but also if the two configs // are identical (diff == 0), or overlay packages will not take effect. continue; } bestItem = thisConfig; bestValue = item; bestPackage = package; } TABLE_NOISY(printf("Found result: package %p\n", bestPackage)); if (bestValue) { outValue->size = dtohs(bestValue->size); outValue->res0 = bestValue->res0; outValue->dataType = bestValue->dataType; outValue->data = dtohl(bestValue->data); if (outConfig != NULL) { *outConfig = bestItem; } TABLE_NOISY(size_t len; printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n", bestPackage->header->index, outValue->dataType, outValue->dataType == bestValue->TYPE_STRING ? String8(bestPackage->header->values.stringAt( outValue->data, &len)).string() : "", outValue->data)); rc = bestPackage->header->index; goto out; } out: if (overrideConfig != NULL) { free(overrideConfig); } return rc; } ssize_t ResTable::getEntry( const Package* package, int typeIndex, int entryIndex, const ResTable_config* config, const ResTable_type** outType, const ResTable_entry** outEntry, const Type** outTypeClass) const { ALOGV("Getting entry from package %p\n", package); const ResTable_package* const pkg = package->package; const Type* allTypes = package->getType(typeIndex); ALOGV("allTypes=%p\n", allTypes); if (allTypes == NULL) { ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex); return 0; } if ((size_t)entryIndex >= allTypes->entryCount) { ALOGW("getEntry failing because entryIndex %d is beyond type entryCount %d", entryIndex, (int)allTypes->entryCount); return BAD_TYPE; } const ResTable_type* type = NULL; uint32_t offset = ResTable_type::NO_ENTRY; ResTable_config bestConfig; memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up const size_t NT = allTypes->configs.size(); for (size_t i=0; i<NT; i++) { const ResTable_type* const thisType = allTypes->configs[i]; if (thisType == NULL) continue; ResTable_config thisConfig; thisConfig.copyFromDtoH(thisType->config); TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n", entryIndex, typeIndex+1, dtohl(thisType->config.size), thisConfig.toString().string())); // Check to make sure this one is valid for the current parameters. if (config && !thisConfig.match(*config)) { TABLE_GETENTRY(ALOGI("Does not match config!\n")); continue; }//重要 // Check if there is the desired entry in this type. const uint8_t* const end = ((const uint8_t*)thisType) + dtohl(thisType->header.size); const uint32_t* const eindex = (const uint32_t*) (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize)); uint32_t thisOffset = dtohl(eindex[entryIndex]); if (thisOffset == ResTable_type::NO_ENTRY) { TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n")); continue; } if (type != NULL) { // Check if this one is less specific than the last found. If so, // we will skip it. We check starting with things we most care // about to those we least care about. if (!thisConfig.isBetterThan(bestConfig, config)) { TABLE_GETENTRY(ALOGI("This config is worse than last!\n")); continue; } } type = thisType; offset = thisOffset; bestConfig = thisConfig; TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n")); if (!config) break; } if (type == NULL) { TABLE_GETENTRY(ALOGI("No value found for requested entry!\n")); return BAD_INDEX; } offset += dtohl(type->entriesStart); TABLE_NOISY(aout << "Looking in resource table " << package->header->header << ", typeOff=" << (void*)(((const char*)type)-((const char*)package->header->header)) << ", offset=" << (void*)offset << endl); if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) { ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x", offset, dtohl(type->header.size)); return BAD_TYPE; } if ((offset&0x3) != 0) { ALOGW("ResTable_entry at 0x%x is not on an integer boundary", offset); return BAD_TYPE; } const ResTable_entry* const entry = (const ResTable_entry*) (((const uint8_t*)type) + offset); if (dtohs(entry->size) < sizeof(*entry)) { ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size)); return BAD_TYPE; } *outType = type; *outEntry = entry; if (outTypeClass != NULL) { *outTypeClass = allTypes; } return offset + dtohs(entry->size); }