summaryrefslogtreecommitdiff
path: root/core/jni
diff options
context:
space:
mode:
authorRyan Mitchell <rtmitchell@google.com>2020-11-16 23:08:18 +0000
committerRyan Mitchell <rtmitchell@google.com>2020-12-08 16:58:12 +0000
commit80094e39f90801c44cd80ab0f98df505828ea1f3 (patch)
treee70d5241691a509ce9cf774dc39ce85932fdd1d2 /core/jni
parentec7e7f5622e3444a3003db20ddfd8f5745971fa7 (diff)
Revert^2 "libandroidfw hardening for IncFs"
55ef6167a2c235bd88c7216238b2001b46795b79 Change-Id: I02d4890d181655dfd0a14c188468db512559d27b Merged-In: I02d4890d181655dfd0a14c188468db512559d27b
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp14
-rw-r--r--core/jni/android_util_AssetManager.cpp417
-rw-r--r--core/jni/android_util_AssetManager_private.h54
-rw-r--r--core/jni/android_util_StringBlock.cpp103
4 files changed, 337 insertions, 251 deletions
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index fbdd4060d7f2..444bb668dc57 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -24,6 +24,7 @@
#include "utils/misc.h"
#include "utils/Trace.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/ScopedUtfChars.h"
@@ -347,12 +348,17 @@ static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring fil
return 0;
}
+ const auto buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ 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();
-
+ auto xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index efca33aaf520..b2c69a0aeafd 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -42,6 +42,7 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/ResourceUtils.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/JNIPlatformHelp.h"
@@ -112,19 +113,17 @@ constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie)
return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
}
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
- uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
+static jint CopyValue(JNIEnv* env, const AssetManager2::SelectedValue& value,
+ jobject out_typed_value) {
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.type);
env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
- ApkAssetsCookieToJavaCookie(cookie));
+ ApkAssetsCookieToJavaCookie(value.cookie));
env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
- if (config != nullptr) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
- }
- return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, value.resid);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, value.flags);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, value.config.density);
+ return static_cast<jint>(ApkAssetsCookieToJavaCookie(value.cookie));
}
// ----------------------------------------------------------------------------
@@ -569,15 +568,15 @@ static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint
return 0;
}
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
-
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -606,15 +605,15 @@ static jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
-
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -626,67 +625,62 @@ static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
jshort density, jobject typed_value,
jboolean resolve_references) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
- static_cast<uint16_t>(density), &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
+ static_cast<uint16_t>(density));
+ if (!value.has_value()) {
+ ThrowIfIOError(env, value);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = static_cast<uint32_t>(resid);
if (resolve_references) {
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ auto result = assetmanager->ResolveReference(value.value());
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
}
- return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
+ return CopyValue(env, *value, typed_value);
}
static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jint bag_entry_id, jobject typed_value) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t type_spec_flags = bag->type_spec_flags;
- ApkAssetsCookie cookie = kInvalidCookie;
- const Res_value* bag_value = nullptr;
- for (const ResolvedBag::Entry& entry : bag) {
- if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
- cookie = entry.cookie;
- bag_value = &entry.value;
-
- // Keep searching (the old implementation did that).
- }
- }
+ // The legacy would find the last entry with the target bag entry id
+ using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
+ const auto rbegin = reverse_bag_iterator(end(*bag));
+ const auto rend = reverse_bag_iterator(begin(*bag));
+ auto entry = std::find_if(rbegin, rend, [bag_entry_id](auto&& e) {
+ return e.key == static_cast<uint32_t>(bag_entry_id);
+ });
- if (cookie == kInvalidCookie) {
+ if (entry == rend) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- Res_value value = *bag_value;
- uint32_t ref = static_cast<uint32_t>(resid);
- ResTable_config selected_config;
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(*bag, *entry);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
+ return CopyValue(env, attr_value, typed_value);
}
static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (env->ExceptionCheck()) {
return nullptr;
@@ -702,42 +696,47 @@ static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong p
static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
if (array == nullptr) {
return nullptr;
}
for (uint32_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
-
// Resolve any references to their final value.
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType == Res_value::TYPE_STRING) {
- const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ const ApkAssets* apk_assets = assetmanager->GetApkAssets()[attr_value.cookie];
const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
jstring java_string = nullptr;
- size_t str_len;
- const char* str_utf8 = pool->string8At(value.data, &str_len);
- if (str_utf8 != nullptr) {
- java_string = env->NewStringUTF(str_utf8);
+ auto str_utf8 = pool->string8At(attr_value.data);
+ if (UNLIKELY(ThrowIfIOError(env, str_utf8))) {
+ return nullptr;
+ }
+
+ if (str_utf8.has_value()) {
+ java_string = env->NewStringUTF(str_utf8->data());
} else {
- const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
- java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
+ auto str_utf16 = pool->stringAt(attr_value.data);
+ if (!str_utf16.has_value()) {
+ ThrowIfIOError(env, str_utf16);
+ return nullptr;
+ }
+ java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16->data()),
+ str_utf16->size());
}
// Check for errors creating the strings (if malformed or no memory).
@@ -758,11 +757,13 @@ static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/,
static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count * 2);
if (array == nullptr) {
return nullptr;
@@ -774,24 +775,20 @@ static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/,
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ ThrowIfIOError(env, result);
return nullptr;
}
jint string_index = -1;
- if (value.dataType == Res_value::TYPE_STRING) {
- string_index = static_cast<jint>(value.data);
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ string_index = static_cast<jint>(attr_value.data);
}
- buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
+ buffer[i * 2] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
buffer[(i * 2) + 1] = string_index;
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
@@ -800,11 +797,13 @@ static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/,
static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (array == nullptr) {
return nullptr;
@@ -816,40 +815,39 @@ static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ env->ReleasePrimitiveArrayCritical(array, buffer, 0);
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
- buffer[i] = static_cast<jint>(value.data);
+ if (attr_value.type >= Res_value::TYPE_FIRST_INT &&
+ attr_value.type <= Res_value::TYPE_LAST_INT) {
+ buffer[i] = static_cast<jint>(attr_value.data);
}
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
return array;
}
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return -1;
- }
- return static_cast<jint>(bag->entry_count);
+static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
+ return -1;
+ }
+ return static_cast<jint>((*bag)->entry_count);
}
static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jintArray out_data) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return -1;
}
@@ -858,8 +856,10 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
return -1;
}
+ const ResolvedBag* bag = *bag_result;
if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Input array is not large enough");
return -1;
}
@@ -870,31 +870,26 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
jint* cursor = buffer;
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- selected_config.density = 0;
- uint32_t flags = bag->type_spec_flags;
- uint32_t ref = 0;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
+ ThrowIfIOError(env, bag_result);
return -1;
}
// 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;
+ if (attr_value.type == Res_value::TYPE_REFERENCE && attr_value.data == 0) {
+ attr_value.type = Res_value::TYPE_NULL;
+ attr_value.data = Res_value::DATA_NULL_UNDEFINED;
}
- cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
- cursor[STYLE_DATA] = static_cast<jint>(value.data);
- cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
- cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
- cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
+ cursor[STYLE_TYPE] = static_cast<jint>(attr_value.type);
+ cursor[STYLE_DATA] = static_cast<jint>(attr_value.data);
+ cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
+ cursor[STYLE_RESOURCE_ID] = static_cast<jint>(attr_value.resid);
+ cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(attr_value.flags);
+ cursor[STYLE_DENSITY] = static_cast<jint>(attr_value.config.density);
cursor += STYLE_NUM_ENTRIES;
}
env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
@@ -922,60 +917,71 @@ static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr
CHECK(package_utf8.c_str() != nullptr);
package = package_utf8.c_str();
}
+
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
+ auto resid = assetmanager->GetResourceId(name_utf8.c_str(), type, package);
+ if (!resid.has_value()) {
+ ThrowIfIOError(env, resid);
+ return 0;
+ }
+
+ return static_cast<jint>(*resid);
}
static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- std::string result = ToFormattedResourceString(&name);
+ const std::string result = ToFormattedResourceString(name.value());
return env->NewStringUTF(result.c_str());
}
static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.package != nullptr) {
- return env->NewStringUTF(name.package);
+ if (name->package != nullptr) {
+ return env->NewStringUTF(name->package);
}
return nullptr;
}
static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.type != nullptr) {
- return env->NewStringUTF(name.type);
- } else if (name.type16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
+ if (name->type != nullptr) {
+ return env->NewStringUTF(name->type);
+ } else if (name->type16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->type16), name->type_len);
}
return nullptr;
}
static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.entry != nullptr) {
- return env->NewStringUTF(name.entry);
- } else if (name.entry16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
+ if (name->entry != nullptr) {
+ return env->NewStringUTF(name->entry);
+ } else if (name->entry16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->entry16), name->entry_len);
}
return nullptr;
}
@@ -1039,17 +1045,21 @@ static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config&
static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::set<ResTable_config> configurations =
- assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
+ auto configurations = assetmanager->GetResourceConfigurations(true /*exclude_system*/,
+ false /*exclude_mipmap*/);
+ if (!configurations.has_value()) {
+ ThrowIfIOError(env, configurations);
+ return nullptr;
+ }
jobjectArray array =
- env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
+ env->NewObjectArray(configurations->size(), gConfigurationOffsets.classObject, nullptr);
if (array == nullptr) {
return nullptr;
}
size_t idx = 0;
- for (const ResTable_config& configuration : configurations) {
+ for (const ResTable_config& configuration : *configurations) {
jobject java_configuration = ConstructConfigurationObject(env, configuration);
if (java_configuration == nullptr) {
return nullptr;
@@ -1072,13 +1082,10 @@ static jintArray NativeAttributeResolutionStack(
(void) assetmanager;
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
- }
+ auto value = theme->GetAttribute(def_style_attr);
+ if (value.has_value() && value->type == Res_value::TYPE_REFERENCE) {
+ def_style_resid = value->data;
}
}
@@ -1119,10 +1126,11 @@ static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong the
return;
}
- ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
- static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
- out_values, out_indices);
+ auto result = ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid),
+ reinterpret_cast<uint32_t*>(attrs), attrs_len, out_values, out_indices);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ ThrowIfIOError(env, result);
}
static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
@@ -1183,11 +1191,12 @@ static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlo
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
-
- bool result = ResolveAttrs(
- theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
- reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
- attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ ResolveAttrs(theme, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(values),
+ values_len, reinterpret_cast<uint32_t*>(attrs), attrs_len,
+ reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
@@ -1196,8 +1205,13 @@ static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlo
if (values != nullptr) {
env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
}
+
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
@@ -1238,18 +1252,22 @@ static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong pt
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-
- bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
- reinterpret_cast<uint32_t*>(attrs), attrs_len,
- reinterpret_cast<uint32_t*>(out_values),
- reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ RetrieveAttributes(assetmanager.get(), xml_parser, reinterpret_cast<uint32_t*>(attrs),
+ attrs_len, reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
+
env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
@@ -1268,7 +1286,9 @@ static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlon
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+
+ auto result = theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+ ThrowIfIOError(env, result);
// TODO(adamlesinski): Consider surfacing exception when result is failure.
// CTS currently expects no exceptions from this method.
@@ -1281,19 +1301,22 @@ static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manag
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
+ ScopedLock<AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+ CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
+ (void) src_assetmanager;
+
if (dst_asset_manager_ptr != src_asset_manager_ptr) {
ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
(void) dst_assetmanager;
- ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
- CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
- (void) src_assetmanager;
-
- dst_theme->SetTo(*src_theme);
- } else {
- dst_theme->SetTo(*src_theme);
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
+ return;
}
+
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
}
static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
@@ -1308,23 +1331,21 @@ static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong pt
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = theme->GetAttribute(static_cast<uint32_t>(resid));
+ if (!value.has_value()) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = 0u;
- if (resolve_references) {
- ResTable_config selected_config;
- cookie =
- theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
+ if (!resolve_references) {
+ return CopyValue(env, *value, typed_value);
+ }
+
+ auto result = theme->GetAssetManager()->ResolveReference(*value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+ return CopyValue(env, *value, typed_value);
}
static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
diff --git a/core/jni/android_util_AssetManager_private.h b/core/jni/android_util_AssetManager_private.h
new file mode 100644
index 000000000000..153509b98db5
--- /dev/null
+++ b/core/jni/android_util_AssetManager_private.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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 ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
+#define ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
+
+#include <optional>
+
+#include <androidfw/Errors.h>
+#include <android-base/expected.h>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+constexpr const char* kResourcesNotFound = "android/content/res/Resources$NotFoundException";
+constexpr const static char* kIOErrorMessage = "failed to read resources.arsc data";
+
+template <typename T, typename E>
+static bool ThrowIfIOError(JNIEnv* env, const base::expected<T, E>& result) {
+ if constexpr (std::is_same<NullOrIOError, E>::value) {
+ if (IsIOError(result)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ } else {
+ if (!result.has_value()) {
+ static_assert(std::is_same<IOError, E>::value, "Unknown result error type");
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ }
+}
+
+} // namespace android
+
+#endif //ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 760f9e36ed3d..45f6b72b3727 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "StringBlock"
+#include "android_util_AssetManager_private.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <utils/misc.h>
@@ -31,10 +32,8 @@ namespace android {
// ----------------------------------------------------------------------------
-static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
- jbyteArray bArray,
- jint off, jint len)
-{
+static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz, jbyteArray bArray,
+ jint off, jint len) {
if (bArray == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
@@ -59,9 +58,7 @@ static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz
return reinterpret_cast<jlong>(osb);
}
-static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -71,76 +68,84 @@ static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz
return osb->size();
}
-static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
- size_t len;
- const char* str8 = osb->string8At(idx, &len);
- if (str8 != NULL) {
- return env->NewStringUTF(str8);
+ auto str8 = osb->string8At(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str8))) {
+ return 0;
+ } else if (str8.has_value()) {
+ return env->NewStringUTF(str8->data());
}
- const char16_t* str = osb->stringAt(idx, &len);
- if (str == NULL) {
+ auto str = osb->stringAt(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str))) {
+ return 0;
+ } else if (UNLIKELY(!str.has_value())) {
jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
return 0;
}
- return env->NewString((const jchar*)str, len);
+ return env->NewString((const jchar*)str->data(), str->size());
}
-static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return NULL;
}
- const ResStringPool_span* spans = osb->styleAt(idx);
- if (spans == NULL) {
+ auto spans = osb->styleAt(idx);
+ if (!spans.has_value()) {
+ ThrowIfIOError(env, spans);
return NULL;
}
- const ResStringPool_span* pos = spans;
- int num = 0;
- while (pos->name.index != ResStringPool_span::END) {
- num++;
- pos++;
+ jintArray array;
+ {
+ int num = 0;
+ auto pos = *spans;
+ while (true) {
+ if (UNLIKELY(!pos)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return NULL;
+ }
+ if (pos->name.index == ResStringPool_span::END) {
+ break;
+ }
+ num++;
+ pos++;
+ }
+
+ if (num == 0) {
+ return NULL;
+ }
+
+ array = env->NewIntArray((num * sizeof(ResStringPool_span)) / sizeof(jint));
+ if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
+ return NULL;
+ }
}
-
- if (num == 0) {
- return NULL;
+ {
+ int num = 0;
+ static const int numInts = sizeof(ResStringPool_span) / sizeof(jint);
+ while ((*spans)->name.index != ResStringPool_span::END) {
+ env->SetIntArrayRegion(array, num * numInts, numInts, (jint*)spans->unsafe_ptr());
+ (*spans)++;
+ num++;
+ }
}
-
- jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
- if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
- return NULL;
- }
-
- num = 0;
- static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
- while (spans->name.index != ResStringPool_span::END) {
- env->SetIntArrayRegion(array,
- num*numInts, numInts,
- (jint*)spans);
- spans++;
- num++;
- }
-
return array;
}
-static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);