Replace AssetManager with AssetManager2 implementation

Test: Existing CTS tests pass
Test: make libandroidfw_tests
Change-Id: I858f7e1d909c08273b096601136e3f28e15eb5d4
This commit is contained in:
Adam Lesinski
2017-01-23 12:58:11 -08:00
parent d6808dc0c0
commit b20a0ce59f
25 changed files with 3010 additions and 2642 deletions

View File

@@ -55,6 +55,7 @@ import android.content.pm.PackageParserCacheHelper.WriteHelper;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
import android.content.pm.split.SplitAssetLoader;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1639,21 +1640,19 @@ public class PackageParser {
int flags) throws PackageParserException {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
AssetManager assets = null;
ApkAssets apkAssets = null;
XmlResourceParser parser = null;
try {
assets = newConfiguredAssetManager();
int cookie = fd != null
? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
if (cookie == 0) {
try {
apkAssets = fd != null
? ApkAssets.loadFromFd(fd, debugPathName, false, false)
: ApkAssets.loadFromPath(apkPath);
} catch (IOException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
"Failed to parse " + apkPath);
}
final DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
final Signature[] signatures;
final Certificate[][] certificates;
@@ -1682,7 +1681,7 @@ public class PackageParser {
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
IoUtils.closeQuietly(assets);
IoUtils.closeQuietly(apkAssets);
}
}

View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.res;
import android.annotation.NonNull;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* The loaded, immutable, in-memory representation of an APK.
*
* The main implementation is native C++ and there is very little API surface exposed here. The APK
* is mainly accessed via {@link AssetManager}.
*
* Since the ApkAssets instance is immutable, it can be reused and shared across AssetManagers,
* making the creation of AssetManagers very cheap.
* @hide
*/
public final class ApkAssets implements AutoCloseable {
@GuardedBy("this") private long mNativePtr;
@GuardedBy("this") private StringBlock mStringBlock;
/**
* Creates a new ApkAssets instance from the given path on disk.
*
* @param path The path to an APK on disk.
* @return a new instance of ApkAssets.
* @throws IOException if a disk I/O error or parsing error occurred.
*/
public static @NonNull ApkAssets loadFromPath(@NonNull String path) throws IOException {
return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/);
}
/**
* Creates a new ApkAssets instance from the given path on disk.
*
* @param path The path to an APK on disk.
* @param system When true, the APK is loaded as a system APK (framework).
* @return a new instance of ApkAssets.
* @throws IOException if a disk I/O error or parsing error occurred.
*/
public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system)
throws IOException {
return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/);
}
/**
* Creates a new ApkAssets instance from the given path on disk.
*
* @param path The path to an APK on disk.
* @param system When true, the APK is loaded as a system APK (framework).
* @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
* loaded as a shared library.
* @return a new instance of ApkAssets.
* @throws IOException if a disk I/O error or parsing error occurred.
*/
public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system,
boolean forceSharedLibrary) throws IOException {
return new ApkAssets(path, system, forceSharedLibrary, false /*overlay*/);
}
/**
* Creates a new ApkAssets instance from the given file descriptor. Not for use by applications.
*
* Performs a dup of the underlying fd, so you must take care of still closing
* the FileDescriptor yourself (and can do that whenever you want).
*
* @param fd The FileDescriptor of an open, readable APK.
* @param friendlyName The friendly name used to identify this ApkAssets when logging.
* @param system When true, the APK is loaded as a system APK (framework).
* @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
* loaded as a shared library.
* @return a new instance of ApkAssets.
* @throws IOException if a disk I/O error or parsing error occurred.
*/
public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd,
@NonNull String friendlyName, boolean system, boolean forceSharedLibrary)
throws IOException {
return new ApkAssets(fd, friendlyName, system, forceSharedLibrary);
}
/**
* Creates a new ApkAssets instance from the IDMAP at idmapPath. The overlay APK path
* is encoded within the IDMAP.
*
* @param idmapPath Path to the IDMAP of an overlay APK.
* @param system When true, the APK is loaded as a system APK (framework).
* @return a new instance of ApkAssets.
* @throws IOException if a disk I/O error or parsing error occurred.
*/
public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, boolean system)
throws IOException {
return new ApkAssets(idmapPath, system, false /*forceSharedLibrary*/, true /*overlay*/);
}
private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
throws IOException {
Preconditions.checkNotNull(path, "path");
mNativePtr = nativeLoad(path, system, forceSharedLib, overlay);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
}
private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system,
boolean forceSharedLib) throws IOException {
Preconditions.checkNotNull(fd, "fd");
Preconditions.checkNotNull(friendlyName, "friendlyName");
mNativePtr = nativeLoadFromFd(fd, friendlyName, system, forceSharedLib);
mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
}
@NonNull String getAssetPath() {
synchronized (this) {
ensureValidLocked();
return nativeGetAssetPath(mNativePtr);
}
}
CharSequence getStringFromPool(int idx) {
synchronized (this) {
ensureValidLocked();
return mStringBlock.get(idx);
}
}
/**
* Retrieve a parser for a compiled XML file. This is associated with a single APK and
* <em>NOT</em> a full AssetManager. This means that shared-library references will not be
* dynamically assigned runtime package IDs.
*
* @param fileName The path to the file within the APK.
* @return An XmlResourceParser.
* @throws IOException if the file was not found or an error occurred retrieving it.
*/
public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
ensureValidLocked();
long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
XmlResourceParser parser = block.newParser();
// If nativeOpenXml doesn't throw, it will always return a valid native pointer,
// which makes newParser always return non-null. But let's be paranoid.
if (parser == null) {
throw new AssertionError("block.newParser() returned a null parser");
}
return parser;
}
}
}
/**
* Returns false if the underlying APK was changed since this ApkAssets was loaded.
*/
public boolean isUpToDate() {
synchronized (this) {
ensureValidLocked();
return nativeIsUpToDate(mNativePtr);
}
}
/**
* Closes the ApkAssets and destroys the underlying native implementation. Further use of the
* ApkAssets object will cause exceptions to be thrown.
*
* Calling close on an already closed ApkAssets does nothing.
*/
@Override
public void close() {
synchronized (this) {
if (mNativePtr == 0) {
return;
}
mStringBlock = null;
nativeDestroy(mNativePtr);
mNativePtr = 0;
}
}
@Override
protected void finalize() throws Throwable {
if (mNativePtr != 0) {
nativeDestroy(mNativePtr);
}
}
private void ensureValidLocked() {
if (mNativePtr == 0) {
throw new RuntimeException("ApkAssets is closed");
}
}
private static native long nativeLoad(
@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
throws IOException;
private static native long nativeLoadFromFd(@NonNull FileDescriptor fd,
@NonNull String friendlyName, boolean system, boolean forceSharedLib)
throws IOException;
private static native void nativeDestroy(long ptr);
private static native @NonNull String nativeGetAssetPath(long ptr);
private static native long nativeGetStringBlock(long ptr);
private static native boolean nativeIsUpToDate(long ptr);
private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
}

File diff suppressed because it is too large Load Diff

View File

@@ -590,7 +590,7 @@ public class Resources {
*/
@NonNull
public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
int[] res = mResourcesImpl.getAssets().getResourceIntArray(id);
if (res != null) {
return res;
}
@@ -613,13 +613,13 @@ public class Resources {
@NonNull
public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
final ResourcesImpl impl = mResourcesImpl;
int len = impl.getAssets().getArraySize(id);
int len = impl.getAssets().getResourceArraySize(id);
if (len < 0) {
throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
}
TypedArray array = TypedArray.obtain(this, len);
array.mLength = impl.getAssets().retrieveArray(id, array.mData);
array.mLength = impl.getAssets().getResourceArray(id, array.mData);
array.mIndices[0] = 0;
return array;
@@ -1789,8 +1789,7 @@ public class Resources {
// out the attributes from the XML file (applying type information
// contained in the resources and such).
XmlBlock.Parser parser = (XmlBlock.Parser)set;
mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
array.mData, array.mIndices);
mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
array.mXml = parser;

View File

@@ -168,7 +168,6 @@ public class ResourcesImpl {
mDisplayAdjustments = displayAdjustments;
mConfiguration.setToDefaults();
updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
mAssets.ensureStringBlocks();
}
public DisplayAdjustments getDisplayAdjustments() {
@@ -1274,8 +1273,7 @@ public class ResourcesImpl {
void applyStyle(int resId, boolean force) {
synchronized (mKey) {
AssetManager.applyThemeStyle(mTheme, resId, force);
mAssets.applyStyleToTheme(mTheme, resId, force);
mThemeResId = resId;
mKey.append(resId, force);
}
@@ -1284,7 +1282,7 @@ public class ResourcesImpl {
void setTo(ThemeImpl other) {
synchronized (mKey) {
synchronized (other.mKey) {
AssetManager.copyTheme(mTheme, other.mTheme);
AssetManager.nativeThemeCopy(mTheme, other.mTheme);
mThemeResId = other.mThemeResId;
mKey.setTo(other.getKey());
@@ -1307,12 +1305,10 @@ public class ResourcesImpl {
// out the attributes from the XML file (applying type information
// contained in the resources and such).
final XmlBlock.Parser parser = (XmlBlock.Parser) set;
AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
parser != null ? parser.mParseState : 0,
attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs,
array.mDataAddress, array.mIndicesAddress);
array.mTheme = wrapper;
array.mXml = parser;
return array;
}
}
@@ -1329,7 +1325,7 @@ public class ResourcesImpl {
}
final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
array.mTheme = wrapper;
array.mXml = null;
return array;
@@ -1349,14 +1345,14 @@ public class ResourcesImpl {
@Config int getChangingConfigurations() {
synchronized (mKey) {
final @NativeConfig int nativeChangingConfig =
AssetManager.getThemeChangingConfigurations(mTheme);
AssetManager.nativeThemeGetChangingConfigurations(mTheme);
return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
}
}
public void dump(int priority, String tag, String prefix) {
synchronized (mKey) {
AssetManager.dumpTheme(mTheme, priority, tag, prefix);
mAssets.dumpTheme(mTheme, priority, tag, prefix);
}
}
@@ -1385,13 +1381,13 @@ public class ResourcesImpl {
*/
void rebase() {
synchronized (mKey) {
AssetManager.clearTheme(mTheme);
AssetManager.nativeThemeClear(mTheme);
// Reapply the same styles in the same order.
for (int i = 0; i < mKey.mCount; i++) {
final int resId = mKey.mResId[i];
final boolean force = mKey.mForce[i];
AssetManager.applyThemeStyle(mTheme, resId, force);
mAssets.applyStyleToTheme(mTheme, resId, force);
}
}
}

View File

@@ -61,6 +61,15 @@ public class TypedArray {
return attrs;
}
// STYLE_ prefixed constants are offsets within the typed data array.
static final int STYLE_NUM_ENTRIES = 6;
static final int STYLE_TYPE = 0;
static final int STYLE_DATA = 1;
static final int STYLE_ASSET_COOKIE = 2;
static final int STYLE_RESOURCE_ID = 3;
static final int STYLE_CHANGING_CONFIGURATIONS = 4;
static final int STYLE_DENSITY = 5;
private final Resources mResources;
private DisplayMetrics mMetrics;
private AssetManager mAssets;
@@ -78,7 +87,7 @@ public class TypedArray {
private void resize(int len) {
mLength = len;
final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
final int dataLen = len * STYLE_NUM_ENTRIES;
final int indicesLen = len + 1;
final VMRuntime runtime = VMRuntime.getRuntime();
if (mDataAddress == 0 || mData.length < dataLen) {
@@ -166,9 +175,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -203,9 +212,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return null;
} else if (type == TypedValue.TYPE_STRING) {
@@ -242,14 +251,13 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_STRING) {
final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
final int cookie = data[index + STYLE_ASSET_COOKIE];
if (cookie < 0) {
return mXml.getPooledString(
data[index+AssetManager.STYLE_DATA]).toString();
return mXml.getPooledString(data[index + STYLE_DATA]).toString();
}
}
return null;
@@ -274,11 +282,11 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
data[index + STYLE_CHANGING_CONFIGURATIONS]);
if ((changingConfigs & ~allowedChangingConfigs) != 0) {
return null;
}
@@ -320,14 +328,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA] != 0;
return data[index + STYLE_DATA] != 0;
}
final TypedValue v = mValue;
@@ -359,14 +367,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
}
final TypedValue v = mValue;
@@ -396,16 +404,16 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FLOAT) {
return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
return Float.intBitsToFloat(data[index + STYLE_DATA]);
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
}
final TypedValue v = mValue;
@@ -446,15 +454,15 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_STRING) {
final TypedValue value = mValue;
if (getValueAt(index, value)) {
@@ -498,7 +506,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -533,7 +541,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -564,15 +572,15 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -612,15 +620,14 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimension(
data[index + AssetManager.STYLE_DATA], mMetrics);
return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -661,15 +668,14 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelOffset(
data[index + AssetManager.STYLE_DATA], mMetrics);
return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -711,15 +717,14 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -755,16 +760,15 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
data[index+AssetManager.STYLE_DATA], mMetrics);
return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -795,15 +799,14 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type >= TypedValue.TYPE_FIRST_INT
&& type <= TypedValue.TYPE_LAST_INT) {
return data[index+AssetManager.STYLE_DATA];
return data[index + STYLE_DATA];
} else if (type == TypedValue.TYPE_DIMENSION) {
return TypedValue.complexToDimensionPixelSize(
data[index + AssetManager.STYLE_DATA], mMetrics);
return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
}
return defValue;
@@ -833,15 +836,14 @@ public class TypedArray {
}
final int attrIndex = index;
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return defValue;
} else if (type == TypedValue.TYPE_FRACTION) {
return TypedValue.complexToFraction(
data[index+AssetManager.STYLE_DATA], base, pbase);
return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
} else if (type == TypedValue.TYPE_ATTRIBUTE) {
final TypedValue value = mValue;
getValueAt(index, value);
@@ -874,10 +876,10 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
if (data[index + STYLE_TYPE] != TypedValue.TYPE_NULL) {
final int resid = data[index + STYLE_RESOURCE_ID];
if (resid != 0) {
return resid;
}
@@ -902,10 +904,10 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
return data[index + AssetManager.STYLE_DATA];
if (data[index + STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
return data[index + STYLE_DATA];
}
return defValue;
}
@@ -939,7 +941,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -975,7 +977,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
if (value.type == TypedValue.TYPE_ATTRIBUTE) {
throw new UnsupportedOperationException(
"Failed to resolve attribute at index " + index + ": " + value);
@@ -1006,7 +1008,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
return mResources.getTextArray(value.resourceId);
}
return null;
@@ -1027,7 +1029,7 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
return getValueAt(index * STYLE_NUM_ENTRIES, outValue);
}
/**
@@ -1043,8 +1045,8 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
return mData[index + AssetManager.STYLE_TYPE];
index *= STYLE_NUM_ENTRIES;
return mData[index + STYLE_TYPE];
}
/**
@@ -1063,9 +1065,9 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL;
}
@@ -1084,11 +1086,11 @@ public class TypedArray {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= AssetManager.STYLE_NUM_ENTRIES;
index *= STYLE_NUM_ENTRIES;
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
return type != TypedValue.TYPE_NULL
|| data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
|| data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
}
/**
@@ -1109,7 +1111,7 @@ public class TypedArray {
}
final TypedValue value = mValue;
if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
return value;
}
return null;
@@ -1181,16 +1183,16 @@ public class TypedArray {
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
final int index = i * AssetManager.STYLE_NUM_ENTRIES;
if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
final int index = i * STYLE_NUM_ENTRIES;
if (data[index + STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
// Not an attribute, ignore.
continue;
}
// Null the entry so that we can safely call getZzz().
data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
data[index + STYLE_TYPE] = TypedValue.TYPE_NULL;
final int attr = data[index + AssetManager.STYLE_DATA];
final int attr = data[index + STYLE_DATA];
if (attr == 0) {
// Useless data, ignore.
continue;
@@ -1231,45 +1233,44 @@ public class TypedArray {
final int[] data = mData;
final int N = length();
for (int i = 0; i < N; i++) {
final int index = i * AssetManager.STYLE_NUM_ENTRIES;
final int type = data[index + AssetManager.STYLE_TYPE];
final int index = i * STYLE_NUM_ENTRIES;
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
continue;
}
changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
data[index + STYLE_CHANGING_CONFIGURATIONS]);
}
return changingConfig;
}
private boolean getValueAt(int index, TypedValue outValue) {
final int[] data = mData;
final int type = data[index+AssetManager.STYLE_TYPE];
final int type = data[index + STYLE_TYPE];
if (type == TypedValue.TYPE_NULL) {
return false;
}
outValue.type = type;
outValue.data = data[index+AssetManager.STYLE_DATA];
outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
outValue.data = data[index + STYLE_DATA];
outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
outValue.resourceId = data[index + STYLE_RESOURCE_ID];
outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
outValue.density = data[index+AssetManager.STYLE_DENSITY];
data[index + STYLE_CHANGING_CONFIGURATIONS]);
outValue.density = data[index + STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
return true;
}
private CharSequence loadStringValueAt(int index) {
final int[] data = mData;
final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
final int cookie = data[index + STYLE_ASSET_COOKIE];
if (cookie < 0) {
if (mXml != null) {
return mXml.getPooledString(
data[index+AssetManager.STYLE_DATA]);
return mXml.getPooledString(data[index + STYLE_DATA]);
}
return null;
}
return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]);
}
/** @hide */

View File

@@ -16,6 +16,7 @@
package android.content.res;
import android.annotation.Nullable;
import android.util.TypedValue;
import com.android.internal.util.XmlUtils;
@@ -33,7 +34,7 @@ import java.io.Reader;
*
* {@hide}
*/
final class XmlBlock {
final class XmlBlock implements AutoCloseable {
private static final boolean DEBUG=false;
public XmlBlock(byte[] data) {
@@ -48,6 +49,7 @@ final class XmlBlock {
mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
}
@Override
public void close() {
synchronized (this) {
if (mOpen) {
@@ -478,13 +480,13 @@ final class XmlBlock {
* are doing! The given native object must exist for the entire lifetime
* of this newly creating XmlBlock.
*/
XmlBlock(AssetManager assets, long xmlBlock) {
XmlBlock(@Nullable AssetManager assets, long xmlBlock) {
mAssets = assets;
mNative = xmlBlock;
mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
}
private final AssetManager mAssets;
private @Nullable final AssetManager mAssets;
private final long mNative;
/*package*/ final StringBlock mStrings;
private boolean mOpen = true;

View File

@@ -111,8 +111,8 @@ cc_library_shared {
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_EventLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Log.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_PathParser.cpp",
"android_util_Process.cpp",
"android_util_StringBlock.cpp",
@@ -189,6 +189,7 @@ cc_library_shared {
"android_backup_FileBackupHelperBase.cpp",
"android_backup_BackupHelperDispatcher.cpp",
"android_app_backup_FullBackup.cpp",
"android_content_res_ApkAssets.cpp",
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_animation_PropertyValuesHolder.cpp",

View File

@@ -121,6 +121,7 @@ extern int register_android_util_MemoryIntArray(JNIEnv* env);
extern int register_android_util_PathParser(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_content_res_ApkAssets(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
@@ -1340,6 +1341,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
REG_JNI(register_android_text_MeasuredText),

View File

@@ -28,7 +28,7 @@
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include <androidfw/AssetManager2.h>
#include "Utils.h"
#include "FontUtils.h"
@@ -224,7 +224,8 @@ static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong b
NPE_CHECK_RETURN_ZERO(env, jpath);
NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
builder->axes.clear();
return false;
@@ -236,27 +237,33 @@ static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong b
return false;
}
Asset* asset;
if (isAsset) {
asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
} else {
asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
std::unique_ptr<Asset> asset;
{
ScopedLock<AssetManager2> locked_mgr(*mgr);
if (isAsset) {
asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
} else if (cookie > 0) {
// Valid java cookies are 1-based, but AssetManager cookies are 0-based.
asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
Asset::ACCESS_BUFFER);
} else {
asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
}
}
if (NULL == asset) {
if (nullptr == asset) {
builder->axes.clear();
return false;
}
const void* buf = asset->getBuffer(false);
if (NULL == buf) {
delete asset;
builder->axes.clear();
return false;
}
sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
asset.release()));
return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
}

View File

@@ -361,7 +361,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName
code->sdkVersion = sdkVersion;
code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
if (obbDir != NULL) {
dirStr = env->GetStringUTFChars(obbDir, NULL);

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "android-base/unique_fd.h"
#include "androidfw/ApkAssets.h"
#include "utils/misc.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/ScopedUtfChars.h"
using ::android::base::unique_fd;
namespace android {
static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
jboolean force_shared_lib, jboolean overlay) {
ScopedUtfChars path(env, java_path);
if (path.c_str() == nullptr) {
return 0;
}
std::unique_ptr<const ApkAssets> apk_assets;
if (overlay) {
apk_assets = ApkAssets::LoadOverlay(path.c_str(), system);
} else if (force_shared_lib) {
apk_assets = ApkAssets::LoadAsSharedLibrary(path.c_str(), system);
} else {
apk_assets = ApkAssets::Load(path.c_str(), system);
}
if (apk_assets == nullptr) {
std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str());
jniThrowException(env, "java/io/IOException", error_msg.c_str());
return 0;
}
return reinterpret_cast<jlong>(apk_assets.release());
}
static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor,
jstring friendly_name, jboolean system, jboolean force_shared_lib) {
ScopedUtfChars friendly_name_utf8(env, friendly_name);
if (friendly_name_utf8.c_str() == nullptr) {
return 0;
}
int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
if (fd < 0) {
jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
return 0;
}
unique_fd dup_fd(::dup(fd));
if (dup_fd < 0) {
jniThrowIOException(env, errno);
return 0;
}
std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd),
friendly_name_utf8.c_str(),
system, force_shared_lib);
if (apk_assets == nullptr) {
std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
friendly_name_utf8.c_str(), dup_fd.get());
jniThrowException(env, "java/io/IOException", error_msg.c_str());
return 0;
}
return reinterpret_cast<jlong>(apk_assets.release());
}
static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
delete reinterpret_cast<ApkAssets*>(ptr);
}
static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
return env->NewStringUTF(apk_assets->GetPath().c_str());
}
static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
}
static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
(void)apk_assets;
return JNI_TRUE;
}
static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
ScopedUtfChars path_utf8(env, file_name);
if (path_utf8.c_str() == nullptr) {
return 0;
}
const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
Asset::AccessMode::ACCESS_RANDOM);
if (asset == nullptr) {
jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
return 0;
}
// DynamicRefTable is only needed when looking up resource references. Opening an XML file
// directly from an ApkAssets has no notion of proper resource references.
std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
asset.reset();
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
}
return reinterpret_cast<jlong>(xml_tree.release());
}
// JNI registration.
static const JNINativeMethod gApkAssetsMethods[] = {
{"nativeLoad", "(Ljava/lang/String;ZZZ)J", (void*)NativeLoad},
{"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZ)J",
(void*)NativeLoadFromFd},
{"nativeDestroy", "(J)V", (void*)NativeDestroy},
{"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
{"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
{"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
{"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
};
int register_android_content_res_ApkAssets(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
arraysize(gApkAssetsMethods));
}
} // namespace android

File diff suppressed because it is too large Load Diff

View File

@@ -14,17 +14,20 @@
* limitations under the License.
*/
#ifndef android_util_AssetManager_H
#define android_util_AssetManager_H
#ifndef ANDROID_RUNTIME_ASSETMANAGER_H
#define ANDROID_RUNTIME_ASSETMANAGER_H
#include <androidfw/AssetManager.h>
#include "androidfw/AssetManager2.h"
#include "androidfw/MutexGuard.h"
#include "jni.h"
namespace android {
extern AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject assetMgr);
extern AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
extern Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
extern Guarded<AssetManager2>* AssetManagerForNdkAssetManager(AAssetManager* assetmanager);
}
} // namespace android
#endif
#endif // ANDROID_RUNTIME_ASSETMANAGER_H

View File

@@ -265,8 +265,6 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
bool stop_at_first_match, FindEntryResult* out_entry) {
ATRACE_CALL();
// Might use this if density_override != 0.
ResTable_config density_override_config;
@@ -429,9 +427,7 @@ ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_valu
for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
in_out_value->data != 0u && iteration < kMaxIterations;
iteration++) {
if (out_last_reference != nullptr) {
*out_last_reference = in_out_value->data;
}
*out_last_reference = in_out_value->data;
uint32_t new_flags = 0u;
cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
in_out_value, in_out_selected_config, &new_flags);

View File

@@ -20,13 +20,18 @@
#include <log/log.h>
#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeFinder.h"
#include "androidfw/ResourceTypes.h"
constexpr bool kDebugStyles = false;
namespace android {
// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
}
class XmlAttributeFinder
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
@@ -44,58 +49,53 @@ class XmlAttributeFinder
};
class BagAttributeFinder
: public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
: public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
public:
BagAttributeFinder(const ResTable::bag_entry* start,
const ResTable::bag_entry* end)
: BackTrackingAttributeFinder(start, end) {}
BagAttributeFinder(const ResolvedBag* bag)
: BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
}
inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
return entry->map.name.ident;
inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
return entry->key;
}
};
bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
uint32_t def_style_res, uint32_t* src_values,
size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values,
uint32_t* out_indices) {
bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
if (kDebugStyles) {
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
def_style_attr, def_style_res);
}
const ResTable& res = theme->getResTable();
AssetManager2* assetmanager = theme->GetAssetManager();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
uint32_t def_style_bag_type_set_flags = 0;
uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
Res_value value;
if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
def_style_res = value.data;
}
}
}
// Now lock down the resource object and start pulling stuff from it.
res.lock();
// Retrieve the default style bag, if requested.
const ResTable::bag_entry* def_style_start = nullptr;
uint32_t def_style_type_set_flags = 0;
ssize_t bag_off = def_style_res != 0
? res.getBagLocked(def_style_res, &def_style_start,
&def_style_type_set_flags)
: -1;
def_style_type_set_flags |= def_style_bag_type_set_flags;
const ResTable::bag_entry* const def_style_end =
def_style_start + (bag_off >= 0 ? bag_off : 0);
BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
const ResolvedBag* default_style_bag = nullptr;
if (def_style_res != 0) {
default_style_bag = assetmanager->GetBag(def_style_res);
if (default_style_bag != nullptr) {
def_style_flags |= default_style_bag->type_spec_flags;
}
}
BagAttributeFinder def_style_attr_finder(default_style_bag);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -106,7 +106,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
ssize_t block = -1;
ApkAssetsCookie cookie = kInvalidCookie;
uint32_t type_set_flags = 0;
value.dataType = Res_value::TYPE_NULL;
@@ -122,15 +122,14 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
value.dataType = Res_value::TYPE_ATTRIBUTE;
value.data = src_values[ii];
if (kDebugStyles) {
ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
value.data);
ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else {
const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
if (def_style_entry != def_style_end) {
block = def_style_entry->stringBlock;
type_set_flags = def_style_type_set_flags;
value = def_style_entry->map.value;
const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
cookie = entry->cookie;
type_set_flags = def_style_flags;
value = entry->value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -140,22 +139,26 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
ssize_t new_block =
theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
if (new_block >= 0) block = new_block;
ApkAssetsCookie new_cookie =
theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
if (new_cookie != kInvalidCookie) {
cookie = new_cookie;
}
if (kDebugStyles) {
ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find
// it in the theme!
ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
if (new_block >= 0) {
// If we still don't have a value for this attribute, try to find it in the theme!
ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
if (new_cookie != kInvalidCookie) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
if (new_block >= 0) block = new_block;
new_cookie =
assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
if (new_cookie != kInvalidCookie) {
cookie = new_cookie;
}
if (kDebugStyles) {
ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -169,7 +172,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
block = -1;
cookie = kInvalidCookie;
}
if (kDebugStyles) {
@@ -179,9 +182,7 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
out_values[STYLE_ASSET_COOKIE] =
block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
: static_cast<uint32_t>(-1);
out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -195,90 +196,80 @@ bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
out_values += STYLE_NUM_ENTRIES;
}
res.unlock();
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
return true;
}
void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices) {
if (kDebugStyles) {
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
theme, def_style_attr, def_style_res, xml_parser);
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
def_style_attr, def_style_resid, xml_parser);
}
const ResTable& res = theme->getResTable();
AssetManager2* assetmanager = theme->GetAssetManager();
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Load default style from attribute, if specified...
uint32_t def_style_bag_type_set_flags = 0;
uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
Res_value value;
if (theme->getAttribute(def_style_attr, &value,
&def_style_bag_type_set_flags) >= 0) {
if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
def_style_res = value.data;
def_style_resid = value.data;
}
}
}
// Retrieve the style class associated with the current XML tag.
int style = 0;
uint32_t style_bag_type_set_flags = 0;
// Retrieve the style resource ID associated with the current XML tag's style attribute.
uint32_t style_resid = 0u;
uint32_t style_flags = 0u;
if (xml_parser != nullptr) {
ssize_t idx = xml_parser->indexOfStyle();
if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
if (value.dataType == value.TYPE_ATTRIBUTE) {
if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
// Resolve the attribute with out theme.
if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
value.dataType = Res_value::TYPE_NULL;
}
}
if (value.dataType == value.TYPE_REFERENCE) {
style = value.data;
style_resid = value.data;
}
}
}
// Now lock down the resource object and start pulling stuff from it.
res.lock();
// Retrieve the default style bag, if requested.
const ResTable::bag_entry* def_style_attr_start = nullptr;
uint32_t def_style_type_set_flags = 0;
ssize_t bag_off = def_style_res != 0
? res.getBagLocked(def_style_res, &def_style_attr_start,
&def_style_type_set_flags)
: -1;
def_style_type_set_flags |= def_style_bag_type_set_flags;
const ResTable::bag_entry* const def_style_attr_end =
def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
BagAttributeFinder def_style_attr_finder(def_style_attr_start,
def_style_attr_end);
const ResolvedBag* default_style_bag = nullptr;
if (def_style_resid != 0) {
default_style_bag = assetmanager->GetBag(def_style_resid);
if (default_style_bag != nullptr) {
def_style_flags |= default_style_bag->type_spec_flags;
}
}
BagAttributeFinder def_style_attr_finder(default_style_bag);
// Retrieve the style class bag, if requested.
const ResTable::bag_entry* style_attr_start = nullptr;
uint32_t style_type_set_flags = 0;
bag_off =
style != 0
? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
: -1;
style_type_set_flags |= style_bag_type_set_flags;
const ResTable::bag_entry* const style_attr_end =
style_attr_start + (bag_off >= 0 ? bag_off : 0);
BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
const ResolvedBag* xml_style_bag = nullptr;
if (style_resid != 0) {
xml_style_bag = assetmanager->GetBag(style_resid);
if (xml_style_bag != nullptr) {
style_flags |= xml_style_bag->type_spec_flags;
}
}
BagAttributeFinder xml_style_attr_finder(xml_style_bag);
// Retrieve the XML attributes, if requested.
static const ssize_t kXmlBlock = 0x10000000;
XmlAttributeFinder xml_attr_finder(xml_parser);
const size_t xml_attr_end =
xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
@@ -289,8 +280,8 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
}
ssize_t block = kXmlBlock;
uint32_t type_set_flags = 0;
ApkAssetsCookie cookie = kInvalidCookie;
uint32_t type_set_flags = 0u;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -302,7 +293,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
// Walk through the xml attributes looking for the requested attribute.
const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
if (xml_attr_idx != xml_attr_end) {
if (xml_attr_idx != xml_attr_finder.end()) {
// We found the attribute we were looking for.
xml_parser->getAttributeValue(xml_attr_idx, &value);
if (kDebugStyles) {
@@ -312,12 +303,12 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the style class values looking for the requested attribute.
const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
if (style_attr_entry != style_attr_end) {
const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
if (entry != xml_style_attr_finder.end()) {
// We found the attribute we were looking for.
block = style_attr_entry->stringBlock;
type_set_flags = style_type_set_flags;
value = style_attr_entry->map.value;
cookie = entry->cookie;
type_set_flags = style_flags;
value = entry->value;
if (kDebugStyles) {
ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
@@ -326,25 +317,25 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the default style values looking for the requested attribute.
const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
if (def_style_attr_entry != def_style_attr_end) {
const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
// We found the attribute we were looking for.
block = def_style_attr_entry->stringBlock;
type_set_flags = style_type_set_flags;
value = def_style_attr_entry->map.value;
cookie = entry->cookie;
type_set_flags = def_style_flags;
value = entry->value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
uint32_t resid = 0;
uint32_t resid = 0u;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
ssize_t new_block =
theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
if (new_block >= 0) {
block = new_block;
ApkAssetsCookie new_cookie =
theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
if (new_cookie != kInvalidCookie) {
cookie = new_cookie;
}
if (kDebugStyles) {
@@ -352,14 +343,15 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
}
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
if (new_block >= 0) {
ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
if (new_cookie != kInvalidCookie) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
if (new_block >= 0) {
block = new_block;
new_cookie =
assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
if (new_cookie != kInvalidCookie) {
cookie = new_cookie;
}
if (kDebugStyles) {
@@ -375,7 +367,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
}
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
block = kXmlBlock;
cookie = kInvalidCookie;
}
if (kDebugStyles) {
@@ -385,9 +377,7 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
out_values[STYLE_ASSET_COOKIE] =
block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
: static_cast<uint32_t>(-1);
out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -402,36 +392,28 @@ void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_s
out_values += STYLE_NUM_ENTRIES;
}
res.unlock();
// out_indices must NOT be nullptr.
out_indices[0] = indices_idx;
}
bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices) {
bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
ResTable_config config;
Res_value value;
int indices_idx = 0;
// Now lock down the resource object and start pulling stuff from it.
res->lock();
// Retrieve the XML attributes, if requested.
const size_t xml_attr_count = xml_parser->getAttributeCount();
size_t ix = 0;
uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
static const ssize_t kXmlBlock = 0x10000000;
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
ssize_t block = kXmlBlock;
uint32_t type_set_flags = 0;
ApkAssetsCookie cookie = kInvalidCookie;
uint32_t type_set_flags = 0u;
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -450,28 +432,27 @@ bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
cur_xml_attr = xml_parser->getAttributeNameResID(ix);
}
uint32_t resid = 0;
uint32_t resid = 0u;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
// printf("Resolving attribute reference\n");
ssize_t new_block = res->resolveReference(&value, block, &resid,
&type_set_flags, &config);
if (new_block >= 0) block = new_block;
ApkAssetsCookie new_cookie =
assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
if (new_cookie != kInvalidCookie) {
cookie = new_cookie;
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
block = kXmlBlock;
cookie = kInvalidCookie;
}
// Write the final value back to Java.
out_values[STYLE_TYPE] = value.dataType;
out_values[STYLE_DATA] = value.data;
out_values[STYLE_ASSET_COOKIE] =
block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
: static_cast<uint32_t>(-1);
out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
@@ -485,8 +466,6 @@ bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
out_values += STYLE_NUM_ENTRIES;
}
res->unlock();
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}

View File

@@ -324,8 +324,6 @@ bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_i
bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
FindEntryResult* out_entry) const {
ATRACE_CALL();
// If the type IDs are offset in this package, we need to take that into account when searching
// for a type.
const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];

View File

@@ -58,6 +58,7 @@ class BackTrackingAttributeFinder {
BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
Iterator Find(uint32_t attr);
inline Iterator end();
private:
void JumpToClosestAttribute(uint32_t package_id);
@@ -201,6 +202,11 @@ Iterator BackTrackingAttributeFinder<Derived, Iterator>::Find(uint32_t attr) {
return end_;
}
template <typename Derived, typename Iterator>
Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() {
return end_;
}
} // namespace android
#endif // ANDROIDFW_ATTRIBUTE_FINDER_H

View File

@@ -17,7 +17,8 @@
#ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
#define ANDROIDFW_ATTRIBUTERESOLUTION_H
#include <androidfw/ResourceTypes.h>
#include "androidfw/AssetManager2.h"
#include "androidfw/ResourceTypes.h"
namespace android {
@@ -42,19 +43,19 @@ enum {
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` is NOT optional and must NOT be nullptr.
void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
} // namespace android

View File

@@ -45,16 +45,17 @@ struct FindEntryResult {
// A pointer to the resource table entry for this resource.
// If the size of the entry is > sizeof(ResTable_entry), it can be cast to
// a ResTable_map_entry and processed as a bag/map.
const ResTable_entry* entry = nullptr;
const ResTable_entry* entry;
// The configuration for which the resulting entry was defined.
const ResTable_config* config = nullptr;
// The configuration for which the resulting entry was defined. This points to a structure that
// is already swapped to host endianness.
const ResTable_config* config;
// Stores the resulting bitmask of configuration axis with which the resource value varies.
uint32_t type_flags = 0u;
// The bitmask of configuration axis with which the resource value varies.
uint32_t type_flags;
// The dynamic package ID map for the package from which this resource came from.
const DynamicRefTable* dynamic_ref_table = nullptr;
const DynamicRefTable* dynamic_ref_table;
// The string pool reference to the type's name. This uses a different string pool than
// the global string pool, but this is hidden from the caller.

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROIDFW_MUTEXGUARD_H
#define ANDROIDFW_MUTEXGUARD_H
#include <mutex>
#include <type_traits>
#include "android-base/macros.h"
namespace android {
template <typename T>
class ScopedLock;
// Owns the guarded object and protects access to it via a mutex.
// The guarded object is inaccessible via this class.
// The mutex is locked and the object accessed via the ScopedLock<T> class.
//
// NOTE: The template parameter T should not be a raw pointer, since ownership
// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
//
// Example use:
//
// Guarded<std::string> shared_string("hello");
// {
// ScopedLock<std::string> locked_string(shared_string);
// *locked_string += " world";
// }
//
template <typename T>
class Guarded {
static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
public:
explicit Guarded() : guarded_() {
}
template <typename U = T>
explicit Guarded(const T& guarded,
typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
: guarded_(guarded) {
}
template <typename U = T>
explicit Guarded(T&& guarded,
typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
: guarded_(std::move(guarded)) {
}
private:
friend class ScopedLock<T>;
DISALLOW_COPY_AND_ASSIGN(Guarded);
std::mutex lock_;
T guarded_;
};
template <typename T>
class ScopedLock {
public:
explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
}
T& operator*() {
return guarded_;
}
T* operator->() {
return &guarded_;
}
T* get() {
return &guarded_;
}
private:
DISALLOW_COPY_AND_ASSIGN(ScopedLock);
std::lock_guard<std::mutex> lock_;
T& guarded_;
};
} // namespace android
#endif // ANDROIDFW_MUTEXGUARD_H

View File

@@ -21,6 +21,7 @@
#include "android-base/file.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "androidfw/AssetManager2.h"
#include "TestHelpers.h"
#include "data/styles/R.h"
@@ -32,15 +33,14 @@ namespace android {
class AttributeResolutionTest : public ::testing::Test {
public:
virtual void SetUp() override {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(
GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
1 /*cookie*/, true /*copyData*/));
styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
ASSERT_NE(nullptr, styles_assets_);
assetmanager_.SetApkAssets({styles_assets_.get()});
}
protected:
ResTable table_;
std::unique_ptr<const ApkAssets> styles_assets_;
AssetManager2 assetmanager_;
};
class AttributeResolutionXmlTest : public AttributeResolutionTest {
@@ -48,13 +48,12 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest {
virtual void SetUp() override {
AttributeResolutionTest::SetUp();
std::string contents;
ASSERT_TRUE(
ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
"res/layout/layout.xml", &contents));
std::unique_ptr<Asset> asset =
assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
ASSERT_NE(nullptr, asset);
ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
true /*copyData*/));
ASSERT_EQ(NO_ERROR,
xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
// Skip to the first tag.
while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -66,14 +65,14 @@ class AttributeResolutionXmlTest : public AttributeResolutionTest {
};
TEST_F(AttributeResolutionTest, Theme) {
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
attrs.size(), values.data(), nullptr /*out_indices*/));
@@ -126,8 +125,8 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
nullptr /*out_indices*/));
ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
values.data(), nullptr /*out_indices*/));
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -171,15 +170,15 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
}
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
attrs.size(), values.data(), indices.data());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;

View File

@@ -33,12 +33,12 @@ void GetResourceBenchmarkOld(const std::vector<std::string>& paths, const ResTab
}
}
// Make sure to force creation of the ResTable first, or else the configuration doesn't get set.
const ResTable& table = assetmanager.getResources(true);
if (config != nullptr) {
assetmanager.setConfiguration(*config);
}
const ResTable& table = assetmanager.getResources(true);
Res_value value;
ResTable_config selected_config;
uint32_t flags;

View File

@@ -18,9 +18,11 @@
#include <utils/Log.h>
#include <android/asset_manager_jni.h>
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/Asset.h>
#include <androidfw/AssetDir.h>
#include <androidfw/AssetManager.h>
#include <androidfw/AssetManager2.h>
#include <utils/threads.h>
#include "jni.h"
@@ -35,21 +37,20 @@ using namespace android;
// -----
struct AAssetDir {
AssetDir* mAssetDir;
std::unique_ptr<AssetDir> mAssetDir;
size_t mCurFileIndex;
String8 mCachedFileName;
explicit AAssetDir(AssetDir* dir) : mAssetDir(dir), mCurFileIndex(0) { }
~AAssetDir() { delete mAssetDir; }
explicit AAssetDir(std::unique_ptr<AssetDir> dir) :
mAssetDir(std::move(dir)), mCurFileIndex(0) { }
};
// -----
struct AAsset {
Asset* mAsset;
std::unique_ptr<Asset> mAsset;
explicit AAsset(Asset* asset) : mAsset(asset) { }
~AAsset() { delete mAsset; }
explicit AAsset(std::unique_ptr<Asset> asset) : mAsset(std::move(asset)) { }
};
// -------------------- Public native C API --------------------
@@ -104,19 +105,18 @@ AAsset* AAssetManager_open(AAssetManager* amgr, const char* filename, int mode)
return NULL;
}
AssetManager* mgr = static_cast<AssetManager*>(amgr);
Asset* asset = mgr->open(filename, amMode);
if (asset == NULL) {
return NULL;
ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
std::unique_ptr<Asset> asset = locked_mgr->Open(filename, amMode);
if (asset == nullptr) {
return nullptr;
}
return new AAsset(asset);
return new AAsset(std::move(asset));
}
AAssetDir* AAssetManager_openDir(AAssetManager* amgr, const char* dirName)
{
AssetManager* mgr = static_cast<AssetManager*>(amgr);
return new AAssetDir(mgr->openDir(dirName));
ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
return new AAssetDir(locked_mgr->OpenDir(dirName));
}
/**

View File

@@ -24,8 +24,9 @@
#include <utils/misc.h>
#include <inttypes.h>
#include <android-base/macros.h>
#include <androidfw/Asset.h>
#include <androidfw/AssetManager.h>
#include <androidfw/AssetManager2.h>
#include <androidfw/ResourceTypes.h>
#include <android-base/macros.h>
@@ -1664,18 +1665,22 @@ nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, jlong con, jlong nati
static jlong
nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
{
AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
if (asset == nullptr) {
return 0;
std::unique_ptr<Asset> asset;
{
ScopedLock<AssetManager2> locked_mgr(*mgr);
asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
if (asset == nullptr) {
return 0;
}
}
jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset.release());
return id;
}
@@ -1752,22 +1757,25 @@ static jlong
nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
jfloat fontSize, jint dpi)
{
AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
if (asset == nullptr) {
return 0;
std::unique_ptr<Asset> asset;
{
ScopedLock<AssetManager2> locked_mgr(*mgr);
asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
if (asset == nullptr) {
return 0;
}
}
jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
str.c_str(), str.length(),
fontSize, dpi,
asset->getBuffer(false), asset->getLength());
delete asset;
return id;
}