android 资源获取

 

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);
}

 

 

 

 

 

 

 

你可能感兴趣的:(android,源码分析,resources)