Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2006, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define ATRACE_TAG ATRACE_TAG_RESOURCES
     18 #define LOG_TAG "asset"
     19 
     20 #include <inttypes.h>
     21 #include <linux/capability.h>
     22 #include <stdio.h>
     23 #include <sys/stat.h>
     24 #include <sys/system_properties.h>
     25 #include <sys/types.h>
     26 #include <sys/wait.h>
     27 
     28 #include <private/android_filesystem_config.h> // for AID_SYSTEM
     29 
     30 #include "android-base/logging.h"
     31 #include "android-base/properties.h"
     32 #include "android-base/stringprintf.h"
     33 #include "android_runtime/android_util_AssetManager.h"
     34 #include "android_runtime/AndroidRuntime.h"
     35 #include "android_util_Binder.h"
     36 #include "androidfw/Asset.h"
     37 #include "androidfw/AssetManager.h"
     38 #include "androidfw/AssetManager2.h"
     39 #include "androidfw/AttributeResolution.h"
     40 #include "androidfw/MutexGuard.h"
     41 #include "androidfw/ResourceTypes.h"
     42 #include "core_jni_helpers.h"
     43 #include "jni.h"
     44 #include "nativehelper/JNIHelp.h"
     45 #include "nativehelper/ScopedPrimitiveArray.h"
     46 #include "nativehelper/ScopedStringChars.h"
     47 #include "nativehelper/ScopedUtfChars.h"
     48 #include "utils/Log.h"
     49 #include "utils/misc.h"
     50 #include "utils/String8.h"
     51 #include "utils/Trace.h"
     52 
     53 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
     54 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
     55 
     56 using ::android::base::StringPrintf;
     57 
     58 namespace android {
     59 
     60 // ----------------------------------------------------------------------------
     61 
     62 static struct typedvalue_offsets_t {
     63   jfieldID mType;
     64   jfieldID mData;
     65   jfieldID mString;
     66   jfieldID mAssetCookie;
     67   jfieldID mResourceId;
     68   jfieldID mChangingConfigurations;
     69   jfieldID mDensity;
     70 } gTypedValueOffsets;
     71 
     72 static struct assetfiledescriptor_offsets_t {
     73   jfieldID mFd;
     74   jfieldID mStartOffset;
     75   jfieldID mLength;
     76 } gAssetFileDescriptorOffsets;
     77 
     78 // This is also used by asset_manager.cpp.
     79 assetmanager_offsets_t gAssetManagerOffsets;
     80 
     81 static struct {
     82   jfieldID native_ptr;
     83 } gApkAssetsFields;
     84 
     85 static struct sparsearray_offsets_t {
     86   jclass classObject;
     87   jmethodID constructor;
     88   jmethodID put;
     89 } gSparseArrayOffsets;
     90 
     91 static struct configuration_offsets_t {
     92   jclass classObject;
     93   jmethodID constructor;
     94   jfieldID mSmallestScreenWidthDpOffset;
     95   jfieldID mScreenWidthDpOffset;
     96   jfieldID mScreenHeightDpOffset;
     97 } gConfigurationOffsets;
     98 
     99 jclass g_stringClass = nullptr;
    100 
    101 // ----------------------------------------------------------------------------
    102 
    103 // Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
    104 constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
    105   return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
    106 }
    107 
    108 constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
    109   return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
    110 }
    111 
    112 // This is called by zygote (running as user root) as part of preloadResources.
    113 static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
    114   switch (pid_t pid = fork()) {
    115     case -1:
    116       PLOG(ERROR) << "failed to fork for idmap";
    117       break;
    118 
    119     // child
    120     case 0: {
    121       struct __user_cap_header_struct capheader;
    122       struct __user_cap_data_struct capdata;
    123 
    124       memset(&capheader, 0, sizeof(capheader));
    125       memset(&capdata, 0, sizeof(capdata));
    126 
    127       capheader.version = _LINUX_CAPABILITY_VERSION;
    128       capheader.pid = 0;
    129 
    130       if (capget(&capheader, &capdata) != 0) {
    131         PLOG(ERROR) << "capget";
    132         exit(1);
    133       }
    134 
    135       capdata.effective = capdata.permitted;
    136       if (capset(&capheader, &capdata) != 0) {
    137         PLOG(ERROR) << "capset";
    138         exit(1);
    139       }
    140 
    141       if (setgid(AID_SYSTEM) != 0) {
    142         PLOG(ERROR) << "setgid";
    143         exit(1);
    144       }
    145 
    146       if (setuid(AID_SYSTEM) != 0) {
    147         PLOG(ERROR) << "setuid";
    148         exit(1);
    149       }
    150 
    151       // Generic idmap parameters
    152       const char* argv[8];
    153       int argc = 0;
    154       struct stat st;
    155 
    156       memset(argv, 0, sizeof(argv));
    157       argv[argc++] = AssetManager::IDMAP_BIN;
    158       argv[argc++] = "--scan";
    159       argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
    160       argv[argc++] = AssetManager::TARGET_APK_PATH;
    161       argv[argc++] = AssetManager::IDMAP_DIR;
    162 
    163       // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
    164       // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
    165       std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
    166                                                          "");
    167       if (!overlay_theme_path.empty()) {
    168         overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
    169         if (stat(overlay_theme_path.c_str(), &st) == 0) {
    170           argv[argc++] = overlay_theme_path.c_str();
    171         }
    172       }
    173 
    174       if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
    175         argv[argc++] = AssetManager::OVERLAY_DIR;
    176       }
    177 
    178       if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
    179         argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
    180       }
    181 
    182       // Finally, invoke idmap (if any overlay directory exists)
    183       if (argc > 5) {
    184         execv(AssetManager::IDMAP_BIN, (char* const*)argv);
    185         PLOG(ERROR) << "failed to execv for idmap";
    186         exit(1); // should never get here
    187       } else {
    188         exit(0);
    189       }
    190   } break;
    191 
    192   // parent
    193   default:
    194     waitpid(pid, nullptr, 0);
    195     break;
    196   }
    197 }
    198 
    199 static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
    200                       uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
    201   env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
    202   env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
    203                    ApkAssetsCookieToJavaCookie(cookie));
    204   env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
    205   env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
    206   env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
    207   env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
    208   if (config != nullptr) {
    209     env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
    210   }
    211   return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
    212 }
    213 
    214 // ----------------------------------------------------------------------------
    215 
    216 // Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
    217 struct GuardedAssetManager : public ::AAssetManager {
    218   Guarded<AssetManager2> guarded_assetmanager;
    219 };
    220 
    221 ::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
    222   jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
    223   ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
    224   if (am == nullptr) {
    225     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
    226     return nullptr;
    227   }
    228   return am;
    229 }
    230 
    231 Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
    232   if (assetmanager == nullptr) {
    233     return nullptr;
    234   }
    235   return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
    236 }
    237 
    238 Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
    239   return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
    240 }
    241 
    242 static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
    243   return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
    244 }
    245 
    246 static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
    247                                           jlongArray out_offsets) {
    248   off64_t start_offset, length;
    249   int fd = asset->openFileDescriptor(&start_offset, &length);
    250   asset.reset();
    251 
    252   if (fd < 0) {
    253     jniThrowException(env, "java/io/FileNotFoundException",
    254                       "This file can not be opened as a file descriptor; it is probably "
    255                       "compressed");
    256     return nullptr;
    257   }
    258 
    259   jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
    260   if (offsets == nullptr) {
    261     close(fd);
    262     return nullptr;
    263   }
    264 
    265   offsets[0] = start_offset;
    266   offsets[1] = length;
    267 
    268   env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
    269 
    270   jobject file_desc = jniCreateFileDescriptor(env, fd);
    271   if (file_desc == nullptr) {
    272     close(fd);
    273     return nullptr;
    274   }
    275   return newParcelFileDescriptor(env, file_desc);
    276 }
    277 
    278 static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
    279   return Asset::getGlobalCount();
    280 }
    281 
    282 static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
    283   String8 alloc = Asset::getAssetAllocations();
    284   if (alloc.length() <= 0) {
    285     return nullptr;
    286   }
    287   return env->NewStringUTF(alloc.string());
    288 }
    289 
    290 static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
    291   // TODO(adamlesinski): Switch to AssetManager2.
    292   return AssetManager::getGlobalCount();
    293 }
    294 
    295 static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
    296   // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
    297   // AssetManager2 in a contiguous block (GuardedAssetManager).
    298   return reinterpret_cast<jlong>(new GuardedAssetManager());
    299 }
    300 
    301 static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
    302   delete reinterpret_cast<GuardedAssetManager*>(ptr);
    303 }
    304 
    305 static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    306                                jobjectArray apk_assets_array, jboolean invalidate_caches) {
    307   ATRACE_NAME("AssetManager::SetApkAssets");
    308 
    309   const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
    310   std::vector<const ApkAssets*> apk_assets;
    311   apk_assets.reserve(apk_assets_len);
    312   for (jsize i = 0; i < apk_assets_len; i++) {
    313     jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
    314     if (obj == nullptr) {
    315       std::string msg = StringPrintf("ApkAssets at index %d is null", i);
    316       jniThrowNullPointerException(env, msg.c_str());
    317       return;
    318     }
    319 
    320     jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
    321     if (env->ExceptionCheck()) {
    322       return;
    323     }
    324     apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
    325   }
    326 
    327   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    328   assetmanager->SetApkAssets(apk_assets, invalidate_caches);
    329 }
    330 
    331 static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
    332                                    jstring locale, jint orientation, jint touchscreen, jint density,
    333                                    jint keyboard, jint keyboard_hidden, jint navigation,
    334                                    jint screen_width, jint screen_height,
    335                                    jint smallest_screen_width_dp, jint screen_width_dp,
    336                                    jint screen_height_dp, jint screen_layout, jint ui_mode,
    337                                    jint color_mode, jint major_version) {
    338   ATRACE_NAME("AssetManager::SetConfiguration");
    339 
    340   ResTable_config configuration;
    341   memset(&configuration, 0, sizeof(configuration));
    342   configuration.mcc = static_cast<uint16_t>(mcc);
    343   configuration.mnc = static_cast<uint16_t>(mnc);
    344   configuration.orientation = static_cast<uint8_t>(orientation);
    345   configuration.touchscreen = static_cast<uint8_t>(touchscreen);
    346   configuration.density = static_cast<uint16_t>(density);
    347   configuration.keyboard = static_cast<uint8_t>(keyboard);
    348   configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
    349   configuration.navigation = static_cast<uint8_t>(navigation);
    350   configuration.screenWidth = static_cast<uint16_t>(screen_width);
    351   configuration.screenHeight = static_cast<uint16_t>(screen_height);
    352   configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
    353   configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
    354   configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
    355   configuration.screenLayout = static_cast<uint8_t>(screen_layout);
    356   configuration.uiMode = static_cast<uint8_t>(ui_mode);
    357   configuration.colorMode = static_cast<uint8_t>(color_mode);
    358   configuration.sdkVersion = static_cast<uint16_t>(major_version);
    359 
    360   if (locale != nullptr) {
    361     ScopedUtfChars locale_utf8(env, locale);
    362     CHECK(locale_utf8.c_str() != nullptr);
    363     configuration.setBcp47Locale(locale_utf8.c_str());
    364   }
    365 
    366   // Constants duplicated from Java class android.content.res.Configuration.
    367   static const jint kScreenLayoutRoundMask = 0x300;
    368   static const jint kScreenLayoutRoundShift = 8;
    369 
    370   // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
    371   // in C++. We must extract the round qualifier out of the Java screenLayout and put it
    372   // into screenLayout2.
    373   configuration.screenLayout2 =
    374       static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
    375 
    376   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    377   assetmanager->SetConfiguration(configuration);
    378 }
    379 
    380 static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
    381   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    382 
    383   jobject sparse_array =
    384         env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
    385 
    386   if (sparse_array == nullptr) {
    387     // An exception is pending.
    388     return nullptr;
    389   }
    390 
    391   assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
    392     jstring jpackage_name = env->NewStringUTF(package_name.c_str());
    393     if (jpackage_name == nullptr) {
    394       // An exception is pending.
    395       return;
    396     }
    397 
    398     env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
    399                         jpackage_name);
    400   });
    401   return sparse_array;
    402 }
    403 
    404 static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
    405   ScopedUtfChars path_utf8(env, path);
    406   if (path_utf8.c_str() == nullptr) {
    407     // This will throw NPE.
    408     return nullptr;
    409   }
    410 
    411   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    412   std::unique_ptr<AssetDir> asset_dir =
    413       assetmanager->OpenDir(path_utf8.c_str());
    414   if (asset_dir == nullptr) {
    415     jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
    416     return nullptr;
    417   }
    418 
    419   const size_t file_count = asset_dir->getFileCount();
    420 
    421   jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
    422   if (array == nullptr) {
    423     return nullptr;
    424   }
    425 
    426   for (size_t i = 0; i < file_count; i++) {
    427     jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
    428 
    429     // Check for errors creating the strings (if malformed or no memory).
    430     if (env->ExceptionCheck()) {
    431      return nullptr;
    432     }
    433 
    434     env->SetObjectArrayElement(array, i, java_string);
    435 
    436     // If we have a large amount of string in our array, we might overflow the
    437     // local reference table of the VM.
    438     env->DeleteLocalRef(java_string);
    439   }
    440   return array;
    441 }
    442 
    443 static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
    444                              jint access_mode) {
    445   ScopedUtfChars asset_path_utf8(env, asset_path);
    446   if (asset_path_utf8.c_str() == nullptr) {
    447     // This will throw NPE.
    448     return 0;
    449   }
    450 
    451   ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
    452 
    453   if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
    454       access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
    455     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    456     return 0;
    457   }
    458 
    459   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    460   std::unique_ptr<Asset> asset =
    461       assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
    462   if (!asset) {
    463     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
    464     return 0;
    465   }
    466   return reinterpret_cast<jlong>(asset.release());
    467 }
    468 
    469 static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
    470                                  jlongArray out_offsets) {
    471   ScopedUtfChars asset_path_utf8(env, asset_path);
    472   if (asset_path_utf8.c_str() == nullptr) {
    473     // This will throw NPE.
    474     return nullptr;
    475   }
    476 
    477   ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
    478 
    479   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    480   std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
    481   if (!asset) {
    482     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
    483     return nullptr;
    484   }
    485   return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
    486 }
    487 
    488 static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
    489                                 jstring asset_path, jint access_mode) {
    490   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    491   ScopedUtfChars asset_path_utf8(env, asset_path);
    492   if (asset_path_utf8.c_str() == nullptr) {
    493     // This will throw NPE.
    494     return 0;
    495   }
    496 
    497   ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
    498 
    499   if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
    500       access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
    501     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    502     return 0;
    503   }
    504 
    505   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    506   std::unique_ptr<Asset> asset;
    507   if (cookie != kInvalidCookie) {
    508     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
    509                                        static_cast<Asset::AccessMode>(access_mode));
    510   } else {
    511     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
    512                                        static_cast<Asset::AccessMode>(access_mode));
    513   }
    514 
    515   if (!asset) {
    516     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
    517     return 0;
    518   }
    519   return reinterpret_cast<jlong>(asset.release());
    520 }
    521 
    522 static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
    523                                     jstring asset_path, jlongArray out_offsets) {
    524   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    525   ScopedUtfChars asset_path_utf8(env, asset_path);
    526   if (asset_path_utf8.c_str() == nullptr) {
    527     // This will throw NPE.
    528     return nullptr;
    529   }
    530 
    531   ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
    532 
    533   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    534   std::unique_ptr<Asset> asset;
    535   if (cookie != kInvalidCookie) {
    536     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
    537   } else {
    538     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
    539   }
    540 
    541   if (!asset) {
    542     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
    543     return nullptr;
    544   }
    545   return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
    546 }
    547 
    548 static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
    549                                 jstring asset_path) {
    550   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    551   ScopedUtfChars asset_path_utf8(env, asset_path);
    552   if (asset_path_utf8.c_str() == nullptr) {
    553     // This will throw NPE.
    554     return 0;
    555   }
    556 
    557   ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
    558 
    559   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    560   std::unique_ptr<Asset> asset;
    561   if (cookie != kInvalidCookie) {
    562     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
    563   } else {
    564     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
    565   }
    566 
    567   if (!asset) {
    568     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
    569     return 0;
    570   }
    571 
    572   // May be nullptr.
    573   const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
    574 
    575   std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
    576   status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
    577   asset.reset();
    578 
    579   if (err != NO_ERROR) {
    580     jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
    581     return 0;
    582   }
    583   return reinterpret_cast<jlong>(xml_tree.release());
    584 }
    585 
    586 static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
    587                                    jshort density, jobject typed_value,
    588                                    jboolean resolve_references) {
    589   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    590   Res_value value;
    591   ResTable_config selected_config;
    592   uint32_t flags;
    593   ApkAssetsCookie cookie =
    594       assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
    595                                 static_cast<uint16_t>(density), &value, &selected_config, &flags);
    596   if (cookie == kInvalidCookie) {
    597     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
    598   }
    599 
    600   uint32_t ref = static_cast<uint32_t>(resid);
    601   if (resolve_references) {
    602     cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
    603     if (cookie == kInvalidCookie) {
    604       return ApkAssetsCookieToJavaCookie(kInvalidCookie);
    605     }
    606   }
    607   return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
    608 }
    609 
    610 static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
    611                                       jint bag_entry_id, jobject typed_value) {
    612   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    613   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    614   if (bag == nullptr) {
    615     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
    616   }
    617 
    618   uint32_t type_spec_flags = bag->type_spec_flags;
    619   ApkAssetsCookie cookie = kInvalidCookie;
    620   const Res_value* bag_value = nullptr;
    621   for (const ResolvedBag::Entry& entry : bag) {
    622     if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
    623       cookie = entry.cookie;
    624       bag_value = &entry.value;
    625 
    626       // Keep searching (the old implementation did that).
    627     }
    628   }
    629 
    630   if (cookie == kInvalidCookie) {
    631     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
    632   }
    633 
    634   Res_value value = *bag_value;
    635   uint32_t ref = static_cast<uint32_t>(resid);
    636   ResTable_config selected_config;
    637   cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
    638   if (cookie == kInvalidCookie) {
    639     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
    640   }
    641   return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
    642 }
    643 
    644 static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    645   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    646   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    647   if (bag == nullptr) {
    648     return nullptr;
    649   }
    650 
    651   jintArray array = env->NewIntArray(bag->entry_count);
    652   if (env->ExceptionCheck()) {
    653     return nullptr;
    654   }
    655 
    656   for (uint32_t i = 0; i < bag->entry_count; i++) {
    657     jint attr_resid = bag->entries[i].key;
    658     env->SetIntArrayRegion(array, i, 1, &attr_resid);
    659   }
    660   return array;
    661 }
    662 
    663 static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    664                                                  jint resid) {
    665   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    666   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    667   if (bag == nullptr) {
    668     return nullptr;
    669   }
    670 
    671   jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
    672   if (array == nullptr) {
    673     return nullptr;
    674   }
    675 
    676   for (uint32_t i = 0; i < bag->entry_count; i++) {
    677     const ResolvedBag::Entry& entry = bag->entries[i];
    678 
    679     // Resolve any references to their final value.
    680     Res_value value = entry.value;
    681     ResTable_config selected_config;
    682     uint32_t flags;
    683     uint32_t ref;
    684     ApkAssetsCookie cookie =
    685         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
    686     if (cookie == kInvalidCookie) {
    687       return nullptr;
    688     }
    689 
    690     if (value.dataType == Res_value::TYPE_STRING) {
    691       const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
    692       const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
    693 
    694       jstring java_string = nullptr;
    695       size_t str_len;
    696       const char* str_utf8 = pool->string8At(value.data, &str_len);
    697       if (str_utf8 != nullptr) {
    698         java_string = env->NewStringUTF(str_utf8);
    699       } else {
    700         const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
    701         java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
    702       }
    703 
    704       // Check for errors creating the strings (if malformed or no memory).
    705       if (env->ExceptionCheck()) {
    706         return nullptr;
    707       }
    708 
    709       env->SetObjectArrayElement(array, i, java_string);
    710 
    711       // If we have a large amount of string in our array, we might overflow the
    712       // local reference table of the VM.
    713       env->DeleteLocalRef(java_string);
    714     }
    715   }
    716   return array;
    717 }
    718 
    719 static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    720                                                   jint resid) {
    721   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    722   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    723   if (bag == nullptr) {
    724     return nullptr;
    725   }
    726 
    727   jintArray array = env->NewIntArray(bag->entry_count * 2);
    728   if (array == nullptr) {
    729     return nullptr;
    730   }
    731 
    732   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
    733   if (buffer == nullptr) {
    734     return nullptr;
    735   }
    736 
    737   for (size_t i = 0; i < bag->entry_count; i++) {
    738     const ResolvedBag::Entry& entry = bag->entries[i];
    739     Res_value value = entry.value;
    740     ResTable_config selected_config;
    741     uint32_t flags;
    742     uint32_t ref;
    743     ApkAssetsCookie cookie =
    744         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
    745     if (cookie == kInvalidCookie) {
    746       env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
    747       return nullptr;
    748     }
    749 
    750     jint string_index = -1;
    751     if (value.dataType == Res_value::TYPE_STRING) {
    752       string_index = static_cast<jint>(value.data);
    753     }
    754 
    755     buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
    756     buffer[(i * 2) + 1] = string_index;
    757   }
    758   env->ReleasePrimitiveArrayCritical(array, buffer, 0);
    759   return array;
    760 }
    761 
    762 static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    763   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    764   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    765   if (bag == nullptr) {
    766     return nullptr;
    767   }
    768 
    769   jintArray array = env->NewIntArray(bag->entry_count);
    770   if (array == nullptr) {
    771     return nullptr;
    772   }
    773 
    774   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
    775   if (buffer == nullptr) {
    776     return nullptr;
    777   }
    778 
    779   for (size_t i = 0; i < bag->entry_count; i++) {
    780     const ResolvedBag::Entry& entry = bag->entries[i];
    781     Res_value value = entry.value;
    782     ResTable_config selected_config;
    783     uint32_t flags;
    784     uint32_t ref;
    785     ApkAssetsCookie cookie =
    786         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
    787     if (cookie == kInvalidCookie) {
    788       env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
    789       return nullptr;
    790     }
    791 
    792     if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
    793       buffer[i] = static_cast<jint>(value.data);
    794     }
    795   }
    796   env->ReleasePrimitiveArrayCritical(array, buffer, 0);
    797   return array;
    798 }
    799 
    800 static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
    801   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    802   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    803   if (bag == nullptr) {
    804     return -1;
    805   }
    806   return static_cast<jint>(bag->entry_count);
    807 }
    808 
    809 static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
    810                                    jintArray out_data) {
    811   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    812   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
    813   if (bag == nullptr) {
    814     return -1;
    815   }
    816 
    817   const jsize out_data_length = env->GetArrayLength(out_data);
    818   if (env->ExceptionCheck()) {
    819     return -1;
    820   }
    821 
    822   if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
    823     jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
    824     return -1;
    825   }
    826 
    827   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
    828   if (buffer == nullptr) {
    829     return -1;
    830   }
    831 
    832   jint* cursor = buffer;
    833   for (size_t i = 0; i < bag->entry_count; i++) {
    834     const ResolvedBag::Entry& entry = bag->entries[i];
    835     Res_value value = entry.value;
    836     ResTable_config selected_config;
    837     selected_config.density = 0;
    838     uint32_t flags = bag->type_spec_flags;
    839     uint32_t ref = 0;
    840     ApkAssetsCookie cookie =
    841         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
    842     if (cookie == kInvalidCookie) {
    843       env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
    844       return -1;
    845     }
    846 
    847     // Deal with the special @null value -- it turns back to TYPE_NULL.
    848     if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
    849       value.dataType = Res_value::TYPE_NULL;
    850       value.data = Res_value::DATA_NULL_UNDEFINED;
    851     }
    852 
    853     cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
    854     cursor[STYLE_DATA] = static_cast<jint>(value.data);
    855     cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
    856     cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
    857     cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
    858     cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
    859     cursor += STYLE_NUM_ENTRIES;
    860   }
    861   env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
    862   return static_cast<jint>(bag->entry_count);
    863 }
    864 
    865 static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
    866                                         jstring def_type, jstring def_package) {
    867   ScopedUtfChars name_utf8(env, name);
    868   if (name_utf8.c_str() == nullptr) {
    869     // This will throw NPE.
    870     return 0;
    871   }
    872 
    873   std::string type;
    874   if (def_type != nullptr) {
    875     ScopedUtfChars type_utf8(env, def_type);
    876     CHECK(type_utf8.c_str() != nullptr);
    877     type = type_utf8.c_str();
    878   }
    879 
    880   std::string package;
    881   if (def_package != nullptr) {
    882     ScopedUtfChars package_utf8(env, def_package);
    883     CHECK(package_utf8.c_str() != nullptr);
    884     package = package_utf8.c_str();
    885   }
    886   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    887   return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
    888 }
    889 
    890 static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    891   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    892   AssetManager2::ResourceName name;
    893   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
    894     return nullptr;
    895   }
    896 
    897   std::string result;
    898   if (name.package != nullptr) {
    899     result.append(name.package, name.package_len);
    900   }
    901 
    902   if (name.type != nullptr || name.type16 != nullptr) {
    903     if (!result.empty()) {
    904       result += ":";
    905     }
    906 
    907     if (name.type != nullptr) {
    908       result.append(name.type, name.type_len);
    909     } else {
    910       result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
    911     }
    912   }
    913 
    914   if (name.entry != nullptr || name.entry16 != nullptr) {
    915     if (!result.empty()) {
    916       result += "/";
    917     }
    918 
    919     if (name.entry != nullptr) {
    920       result.append(name.entry, name.entry_len);
    921     } else {
    922       result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
    923     }
    924   }
    925   return env->NewStringUTF(result.c_str());
    926 }
    927 
    928 static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    929   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    930   AssetManager2::ResourceName name;
    931   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
    932     return nullptr;
    933   }
    934 
    935   if (name.package != nullptr) {
    936     return env->NewStringUTF(name.package);
    937   }
    938   return nullptr;
    939 }
    940 
    941 static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    942   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    943   AssetManager2::ResourceName name;
    944   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
    945     return nullptr;
    946   }
    947 
    948   if (name.type != nullptr) {
    949     return env->NewStringUTF(name.type);
    950   } else if (name.type16 != nullptr) {
    951     return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
    952   }
    953   return nullptr;
    954 }
    955 
    956 static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    957   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    958   AssetManager2::ResourceName name;
    959   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
    960     return nullptr;
    961   }
    962 
    963   if (name.entry != nullptr) {
    964     return env->NewStringUTF(name.entry);
    965   } else if (name.entry16 != nullptr) {
    966     return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
    967   }
    968   return nullptr;
    969 }
    970 
    971 static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
    972                                      jboolean exclude_system) {
    973   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
    974   std::set<std::string> locales =
    975       assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
    976 
    977   jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
    978   if (array == nullptr) {
    979     return nullptr;
    980   }
    981 
    982   size_t idx = 0;
    983   for (const std::string& locale : locales) {
    984     jstring java_string = env->NewStringUTF(locale.c_str());
    985     if (java_string == nullptr) {
    986       return nullptr;
    987     }
    988     env->SetObjectArrayElement(array, idx++, java_string);
    989     env->DeleteLocalRef(java_string);
    990   }
    991   return array;
    992 }
    993 
    994 static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
    995   jobject result =
    996       env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
    997   if (result == nullptr) {
    998     return nullptr;
    999   }
   1000 
   1001   env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
   1002                    config.smallestScreenWidthDp);
   1003   env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
   1004   env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
   1005   return result;
   1006 }
   1007 
   1008 static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
   1009   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1010   std::set<ResTable_config> configurations =
   1011       assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
   1012 
   1013   jobjectArray array =
   1014       env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
   1015   if (array == nullptr) {
   1016     return nullptr;
   1017   }
   1018 
   1019   size_t idx = 0;
   1020   for (const ResTable_config& configuration : configurations) {
   1021     jobject java_configuration = ConstructConfigurationObject(env, configuration);
   1022     if (java_configuration == nullptr) {
   1023       return nullptr;
   1024     }
   1025 
   1026     env->SetObjectArrayElement(array, idx++, java_configuration);
   1027     env->DeleteLocalRef(java_configuration);
   1028   }
   1029   return array;
   1030 }
   1031 
   1032 static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1033                              jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
   1034                              jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
   1035   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1036   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1037   CHECK(theme->GetAssetManager() == &(*assetmanager));
   1038   (void) assetmanager;
   1039 
   1040   ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
   1041   uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
   1042   uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
   1043 
   1044   jsize attrs_len = env->GetArrayLength(java_attrs);
   1045   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
   1046   if (attrs == nullptr) {
   1047     return;
   1048   }
   1049 
   1050   ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
   1051              static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
   1052              out_values, out_indices);
   1053   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1054 }
   1055 
   1056 static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1057                                    jint def_style_attr, jint def_style_resid, jintArray java_values,
   1058                                    jintArray java_attrs, jintArray out_java_values,
   1059                                    jintArray out_java_indices) {
   1060   const jsize attrs_len = env->GetArrayLength(java_attrs);
   1061   const jsize out_values_len = env->GetArrayLength(out_java_values);
   1062   if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
   1063     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
   1064     return JNI_FALSE;
   1065   }
   1066 
   1067   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
   1068   if (attrs == nullptr) {
   1069     return JNI_FALSE;
   1070   }
   1071 
   1072   jint* values = nullptr;
   1073   jsize values_len = 0;
   1074   if (java_values != nullptr) {
   1075     values_len = env->GetArrayLength(java_values);
   1076     values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
   1077     if (values == nullptr) {
   1078       env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1079       return JNI_FALSE;
   1080     }
   1081   }
   1082 
   1083   jint* out_values =
   1084       reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
   1085   if (out_values == nullptr) {
   1086     env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1087     if (values != nullptr) {
   1088       env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1089     }
   1090     return JNI_FALSE;
   1091   }
   1092 
   1093   jint* out_indices = nullptr;
   1094   if (out_java_indices != nullptr) {
   1095     jsize out_indices_len = env->GetArrayLength(out_java_indices);
   1096     if (out_indices_len > attrs_len) {
   1097       out_indices =
   1098           reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
   1099       if (out_indices == nullptr) {
   1100         env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1101         if (values != nullptr) {
   1102           env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1103         }
   1104         env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
   1105         return JNI_FALSE;
   1106       }
   1107     }
   1108   }
   1109 
   1110   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1111   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1112   CHECK(theme->GetAssetManager() == &(*assetmanager));
   1113   (void) assetmanager;
   1114 
   1115   bool result = ResolveAttrs(
   1116       theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
   1117       reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
   1118       attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
   1119   if (out_indices != nullptr) {
   1120     env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
   1121   }
   1122 
   1123   env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
   1124   if (values != nullptr) {
   1125     env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1126   }
   1127   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1128   return result ? JNI_TRUE : JNI_FALSE;
   1129 }
   1130 
   1131 static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
   1132                                          jlong xml_parser_ptr, jintArray java_attrs,
   1133                                          jintArray out_java_values, jintArray out_java_indices) {
   1134   const jsize attrs_len = env->GetArrayLength(java_attrs);
   1135   const jsize out_values_len = env->GetArrayLength(out_java_values);
   1136   if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
   1137     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
   1138     return JNI_FALSE;
   1139   }
   1140 
   1141   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
   1142   if (attrs == nullptr) {
   1143     return JNI_FALSE;
   1144   }
   1145 
   1146   jint* out_values =
   1147       reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
   1148   if (out_values == nullptr) {
   1149     env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1150     return JNI_FALSE;
   1151   }
   1152 
   1153   jint* out_indices = nullptr;
   1154   if (out_java_indices != nullptr) {
   1155     jsize out_indices_len = env->GetArrayLength(out_java_indices);
   1156     if (out_indices_len > attrs_len) {
   1157       out_indices =
   1158           reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
   1159       if (out_indices == nullptr) {
   1160         env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1161         env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
   1162         return JNI_FALSE;
   1163       }
   1164     }
   1165   }
   1166 
   1167   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1168   ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
   1169 
   1170   bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
   1171                                    reinterpret_cast<uint32_t*>(attrs), attrs_len,
   1172                                    reinterpret_cast<uint32_t*>(out_values),
   1173                                    reinterpret_cast<uint32_t*>(out_indices));
   1174 
   1175   if (out_indices != nullptr) {
   1176     env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
   1177   }
   1178   env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
   1179   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1180   return result ? JNI_TRUE : JNI_FALSE;
   1181 }
   1182 
   1183 static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
   1184   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1185   return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
   1186 }
   1187 
   1188 static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
   1189   delete reinterpret_cast<Theme*>(theme_ptr);
   1190 }
   1191 
   1192 static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1193                                   jint resid, jboolean force) {
   1194   // AssetManager is accessed via the theme, so grab an explicit lock here.
   1195   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1196   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1197   CHECK(theme->GetAssetManager() == &(*assetmanager));
   1198   (void) assetmanager;
   1199   theme->ApplyStyle(static_cast<uint32_t>(resid), force);
   1200 
   1201   // TODO(adamlesinski): Consider surfacing exception when result is failure.
   1202   // CTS currently expects no exceptions from this method.
   1203   // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
   1204   // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
   1205 }
   1206 
   1207 static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
   1208                             jlong src_theme_ptr) {
   1209   Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
   1210   Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
   1211   if (!dst_theme->SetTo(*src_theme)) {
   1212     jniThrowException(env, "java/lang/IllegalArgumentException",
   1213                       "Themes are from different AssetManagers");
   1214   }
   1215 }
   1216 
   1217 static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
   1218   reinterpret_cast<Theme*>(theme_ptr)->Clear();
   1219 }
   1220 
   1221 static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1222                                          jint resid, jobject typed_value,
   1223                                          jboolean resolve_references) {
   1224   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1225   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1226   CHECK(theme->GetAssetManager() == &(*assetmanager));
   1227   (void) assetmanager;
   1228 
   1229   Res_value value;
   1230   uint32_t flags;
   1231   ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
   1232   if (cookie == kInvalidCookie) {
   1233     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
   1234   }
   1235 
   1236   uint32_t ref = 0u;
   1237   if (resolve_references) {
   1238     ResTable_config selected_config;
   1239     cookie =
   1240         theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
   1241     if (cookie == kInvalidCookie) {
   1242       return ApkAssetsCookieToJavaCookie(kInvalidCookie);
   1243     }
   1244   }
   1245   return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
   1246 }
   1247 
   1248 static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1249                             jint priority, jstring tag, jstring prefix) {
   1250   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   1251   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1252   CHECK(theme->GetAssetManager() == &(*assetmanager));
   1253   (void) assetmanager;
   1254   (void) theme;
   1255   (void) priority;
   1256   (void) tag;
   1257   (void) prefix;
   1258 }
   1259 
   1260 static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
   1261                                                  jlong theme_ptr) {
   1262   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
   1263   return static_cast<jint>(theme->GetChangingConfigurations());
   1264 }
   1265 
   1266 static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1267   delete reinterpret_cast<Asset*>(asset_ptr);
   1268 }
   1269 
   1270 static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1271   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
   1272   uint8_t b;
   1273   ssize_t res = asset->read(&b, sizeof(b));
   1274   return res == sizeof(b) ? static_cast<jint>(b) : -1;
   1275 }
   1276 
   1277 static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
   1278                             jint offset, jint len) {
   1279   if (len == 0) {
   1280     return 0;
   1281   }
   1282 
   1283   jsize buffer_len = env->GetArrayLength(java_buffer);
   1284   if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
   1285       offset > buffer_len - len) {
   1286     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
   1287     return -1;
   1288   }
   1289 
   1290   ScopedByteArrayRW byte_array(env, java_buffer);
   1291   if (byte_array.get() == nullptr) {
   1292     return -1;
   1293   }
   1294 
   1295   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
   1296   ssize_t res = asset->read(byte_array.get() + offset, len);
   1297   if (res < 0) {
   1298     jniThrowException(env, "java/io/IOException", "");
   1299     return -1;
   1300   }
   1301   return res > 0 ? static_cast<jint>(res) : -1;
   1302 }
   1303 
   1304 static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
   1305                              jint whence) {
   1306   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
   1307   return static_cast<jlong>(asset->seek(
   1308       static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
   1309 }
   1310 
   1311 static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1312   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
   1313   return static_cast<jlong>(asset->getLength());
   1314 }
   1315 
   1316 static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1317   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
   1318   return static_cast<jlong>(asset->getRemainingLength());
   1319 }
   1320 
   1321 // ----------------------------------------------------------------------------
   1322 
   1323 // JNI registration.
   1324 static const JNINativeMethod gAssetManagerMethods[] = {
   1325     // AssetManager setup methods.
   1326     {"nativeCreate", "()J", (void*)NativeCreate},
   1327     {"nativeDestroy", "(J)V", (void*)NativeDestroy},
   1328     {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
   1329     {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
   1330      (void*)NativeSetConfiguration},
   1331     {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
   1332      (void*)NativeGetAssignedPackageIdentifiers},
   1333 
   1334     // AssetManager file methods.
   1335     {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
   1336     {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
   1337     {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1338      (void*)NativeOpenAssetFd},
   1339     {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
   1340     {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1341      (void*)NativeOpenNonAssetFd},
   1342     {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
   1343 
   1344     // AssetManager resource methods.
   1345     {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
   1346     {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
   1347      (void*)NativeGetResourceBagValue},
   1348     {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
   1349     {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
   1350      (void*)NativeGetResourceStringArray},
   1351     {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
   1352     {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
   1353     {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
   1354     {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
   1355 
   1356     // AssetManager resource name/ID methods.
   1357     {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
   1358      (void*)NativeGetResourceIdentifier},
   1359     {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
   1360     {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
   1361     {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
   1362     {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
   1363     {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
   1364     {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
   1365      (void*)NativeGetSizeConfigurations},
   1366 
   1367     // Style attribute related methods.
   1368     {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
   1369     {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
   1370     {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
   1371 
   1372     // Theme related methods.
   1373     {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
   1374     {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
   1375     {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
   1376     {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
   1377     {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
   1378     {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
   1379      (void*)NativeThemeGetAttributeValue},
   1380     {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
   1381     {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
   1382 
   1383     // AssetInputStream methods.
   1384     {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
   1385     {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
   1386     {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
   1387     {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
   1388     {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
   1389     {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
   1390 
   1391     // System/idmap related methods.
   1392     {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
   1393 
   1394     // Global management/debug methods.
   1395     {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
   1396     {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
   1397     {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
   1398 };
   1399 
   1400 int register_android_content_AssetManager(JNIEnv* env) {
   1401   jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
   1402   gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
   1403 
   1404   jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
   1405   gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
   1406   gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
   1407   gTypedValueOffsets.mString =
   1408       GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
   1409   gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
   1410   gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
   1411   gTypedValueOffsets.mChangingConfigurations =
   1412       GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
   1413   gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
   1414 
   1415   jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
   1416   gAssetFileDescriptorOffsets.mFd =
   1417       GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
   1418   gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
   1419   gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
   1420 
   1421   jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
   1422   gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
   1423 
   1424   jclass stringClass = FindClassOrDie(env, "java/lang/String");
   1425   g_stringClass = MakeGlobalRefOrDie(env, stringClass);
   1426 
   1427   jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
   1428   gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
   1429   gSparseArrayOffsets.constructor =
   1430       GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
   1431   gSparseArrayOffsets.put =
   1432       GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
   1433 
   1434   jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
   1435   gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
   1436   gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
   1437   gConfigurationOffsets.mSmallestScreenWidthDpOffset =
   1438       GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
   1439   gConfigurationOffsets.mScreenWidthDpOffset =
   1440       GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
   1441   gConfigurationOffsets.mScreenHeightDpOffset =
   1442       GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
   1443 
   1444   return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
   1445                               NELEM(gAssetManagerMethods));
   1446 }
   1447 
   1448 }; // namespace android
   1449