Replace AssetManager with AssetManager2 implementation
Test: Existing CTS tests pass Test: make libandroidfw_tests Change-Id: I858f7e1d909c08273b096601136e3f28e15eb5d4
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
221
core/java/android/content/res/ApkAssets.java
Normal file
221
core/java/android/content/res/ApkAssets.java
Normal 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
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
150
core/jni/android_content_res_ApkAssets.cpp
Normal file
150
core/jni/android_content_res_ApkAssets.cpp
Normal 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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
101
libs/androidfw/include/androidfw/MutexGuard.h
Normal file
101
libs/androidfw/include/androidfw/MutexGuard.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user