All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.res.android.DynamicRefTable Maven / Gradle / Ivy

package org.robolectric.res.android;

// transliterated from
// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h

import static org.robolectric.res.android.Errors.BAD_TYPE;
import static org.robolectric.res.android.Errors.NO_ERROR;
import static org.robolectric.res.android.Errors.UNKNOWN_ERROR;
import static org.robolectric.res.android.ResTable.APP_PACKAGE_ID;
import static org.robolectric.res.android.ResTable.Res_GETPACKAGE;
import static org.robolectric.res.android.ResTable.SYS_PACKAGE_ID;
import static org.robolectric.res.android.Util.ALOGW;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import org.robolectric.res.android.ResourceTypes.Res_value;

/**
 * Holds the shared library ID table. Shared libraries are assigned package IDs at build time, but
 * they may be loaded in a different order, so we need to maintain a mapping of build-time package
 * ID to run-time assigned package ID.
 *
 * 

Dynamic references are not currently supported in overlays. Only the base package may have * dynamic references. */ public class DynamicRefTable { DynamicRefTable(byte packageId, boolean appAsLib) { this.mAssignedPackageId = packageId; this.mAppAsLib = appAsLib; mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID; mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID; } // // Loads an unmapped reference table from the package. // Errors load(final ResTable_lib_header header) { // return null; // } // Adds mappings from the other DynamicRefTable int addMappings(final DynamicRefTable other) { if (mAssignedPackageId != other.mAssignedPackageId) { return UNKNOWN_ERROR; } // final int entryCount = other.mEntries.size(); // for (size_t i = 0; i < entryCount; i++) { // ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i)); // if (index < 0) { // mEntries.add(other.mEntries.keyAt(i), other.mEntries[i]); // } else { // if (other.mEntries[i] != mEntries[index]) { // return UNKNOWN_ERROR; // } // } // } for (Entry otherEntry : other.mEntries.entrySet()) { String key = otherEntry.getKey(); Byte curValue = mEntries.get(key); if (curValue == null) { mEntries.put(key, otherEntry.getValue()); } else { if (!Objects.equals(otherEntry.getValue(), curValue)) { return UNKNOWN_ERROR; } } } // Merge the lookup table. No entry can conflict // (value of 0 means not set). for (int i = 0; i < 256; i++) { if (mLookupTable[i] != other.mLookupTable[i]) { if (mLookupTable[i] == 0) { mLookupTable[i] = other.mLookupTable[i]; } else if (other.mLookupTable[i] != 0) { return UNKNOWN_ERROR; } } } return NO_ERROR; } // Creates a mapping from build-time package ID to run-time package ID for // the given package. int addMapping(final String packageName, byte packageId) { Byte index = mEntries.get(packageName); if (index == null) { return UNKNOWN_ERROR; } mLookupTable[index] = packageId; return NO_ERROR; } void addAlias(int stagedId, int finalizedId) { mAliasId.put(stagedId, finalizedId); } // // Performs the actual conversion of build-time resource ID to run-time // // resource ID. int lookupResourceId(Ref resId) { int res = resId.get(); int packageId = Res_GETPACKAGE(res) + 1; Integer aliasId = mAliasId.get(res); if (aliasId != null) { // Rewrite the resource id to its alias resource id. Since the alias resource id is a // compile-time id, it still needs to be resolved further. res = aliasId; } if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) { // No lookup needs to be done, app and framework package IDs are absolute. resId.set(res); return NO_ERROR; } if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) { // The package ID is 0x00. That means that a shared library is accessing // its own local resource. // Or if app resource is loaded as shared library, the resource which has // app package Id is local resources. // so we fix up those resources with the calling package ID. resId.set((0xFFFFFF & resId.get()) | (((int) mAssignedPackageId) << 24)); return NO_ERROR; } // Do a proper lookup. int translatedId = mLookupTable[packageId]; if (translatedId == 0) { ALOGW( "DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.", mAssignedPackageId, packageId); for (int i = 0; i < 256; i++) { if (mLookupTable[i] != 0) { ALOGW("e[0x%02x] . 0x%02x", i, mLookupTable[i]); } } return UNKNOWN_ERROR; } resId.set((res & 0x00ffffff) | (((int) translatedId) << 24)); return NO_ERROR; } // int lookupResourceValue(Ref value) { byte resolvedType = DataType.REFERENCE.code(); Res_value inValue = value.get(); DataType dataType; try { dataType = DataType.fromCode(inValue.dataType); } catch (IllegalArgumentException e) { return BAD_TYPE; } switch (dataType) { case ATTRIBUTE: resolvedType = DataType.ATTRIBUTE.code(); // fallthrough case REFERENCE: if (!mAppAsLib) { return NO_ERROR; } // If the package is loaded as shared library, the resource reference // also need to be fixed. break; case DYNAMIC_ATTRIBUTE: resolvedType = DataType.ATTRIBUTE.code(); // fallthrough case DYNAMIC_REFERENCE: break; default: return NO_ERROR; } final Ref resIdRef = new Ref<>(inValue.data); int err = lookupResourceId(resIdRef); value.set(inValue.withData(resIdRef.get())); if (err != NO_ERROR) { return err; } value.set(new Res_value(resolvedType, resIdRef.get())); return NO_ERROR; } public Map entries() { return mEntries; } // // final KeyedVector& entries() final { // return mEntries; // } // // private: final byte mAssignedPackageId; final byte[] mLookupTable = new byte[256]; final Map mEntries = new HashMap<>(); boolean mAppAsLib; final Map mAliasId = new HashMap<>(); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy