diff options
author | Ryan Mitchell <rtmitchell@google.com> | 2020-11-16 23:08:18 +0000 |
---|---|---|
committer | Ryan Mitchell <rtmitchell@google.com> | 2020-12-08 16:58:12 +0000 |
commit | 80094e39f90801c44cd80ab0f98df505828ea1f3 (patch) | |
tree | e70d5241691a509ce9cf774dc39ce85932fdd1d2 /core/jni | |
parent | ec7e7f5622e3444a3003db20ddfd8f5745971fa7 (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.cpp | 14 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 417 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager_private.h | 54 | ||||
-rw-r--r-- | core/jni/android_util_StringBlock.cpp | 103 |
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); |