Revert "Replace AssetManager with AssetManager2 implementation"

This reverts commit 1187590da38457809dd368d4901c9c47ac5a6958.

Bug: 73134570
Change-Id: I59b4d714e447478ea124f086356f127f42251fb7
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c623ca6..683b4c4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1,1441 +1,1851 @@
-/*
- * Copyright 2006, 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.
- */
+/* //device/libs/android_runtime/android_util_AssetManager.cpp
+**
+** Copyright 2006, 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.
+*/
 
 #define LOG_TAG "asset"
 
+#include <android_runtime/android_util_AssetManager.h>
+
 #include <inttypes.h>
 #include <linux/capability.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/system_properties.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/system_properties.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 
-#include "android-base/logging.h"
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
-#include "android_runtime/android_util_AssetManager.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_util_Binder.h"
 #include "androidfw/Asset.h"
 #include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
 #include "androidfw/AttributeResolution.h"
-#include "androidfw/MutexGuard.h"
 #include "androidfw/ResourceTypes.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedStringChars.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "utils/Log.h"
-#include "utils/String8.h"
 #include "utils/misc.h"
+#include "utils/String8.h"
 
 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
 
-using ::android::base::StringPrintf;
 
 namespace android {
 
+static const bool kThrowOnBadId = false;
+
 // ----------------------------------------------------------------------------
 
-static struct typedvalue_offsets_t {
-  jfieldID mType;
-  jfieldID mData;
-  jfieldID mString;
-  jfieldID mAssetCookie;
-  jfieldID mResourceId;
-  jfieldID mChangingConfigurations;
-  jfieldID mDensity;
+static struct typedvalue_offsets_t
+{
+    jfieldID mType;
+    jfieldID mData;
+    jfieldID mString;
+    jfieldID mAssetCookie;
+    jfieldID mResourceId;
+    jfieldID mChangingConfigurations;
+    jfieldID mDensity;
 } gTypedValueOffsets;
 
-static struct assetfiledescriptor_offsets_t {
-  jfieldID mFd;
-  jfieldID mStartOffset;
-  jfieldID mLength;
+static struct assetfiledescriptor_offsets_t
+{
+    jfieldID mFd;
+    jfieldID mStartOffset;
+    jfieldID mLength;
 } gAssetFileDescriptorOffsets;
 
-static struct assetmanager_offsets_t {
-  jfieldID mObject;
+static struct assetmanager_offsets_t
+{
+    jfieldID mObject;
 } gAssetManagerOffsets;
 
-static struct {
-  jfieldID native_ptr;
-} gApkAssetsFields;
-
-static struct sparsearray_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jmethodID put;
+static struct sparsearray_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jmethodID put;
 } gSparseArrayOffsets;
 
-static struct configuration_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jfieldID mSmallestScreenWidthDpOffset;
-  jfieldID mScreenWidthDpOffset;
-  jfieldID mScreenHeightDpOffset;
+static struct configuration_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jfieldID mSmallestScreenWidthDpOffset;
+    jfieldID mScreenWidthDpOffset;
+    jfieldID mScreenHeightDpOffset;
 } gConfigurationOffsets;
 
-jclass g_stringClass = nullptr;
+jclass g_stringClass = NULL;
 
 // ----------------------------------------------------------------------------
 
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
-  return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
-}
+static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+                      const Res_value& value, uint32_t ref, ssize_t block,
+                      uint32_t typeSpecFlags, ResTable_config* config = NULL);
 
-constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
-  return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
+jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+               const Res_value& value, uint32_t ref, ssize_t block,
+               uint32_t typeSpecFlags, ResTable_config* config)
+{
+    env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
+    env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
+                     static_cast<jint>(table->getTableCookie(block)));
+    env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
+    env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
+    env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
+    env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
+            typeSpecFlags);
+    if (config != NULL) {
+        env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
+    }
+    return block;
 }
 
 // This is called by zygote (running as user root) as part of preloadResources.
-static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
-  switch (pid_t pid = fork()) {
-    case -1:
-      PLOG(ERROR) << "failed to fork for idmap";
-      break;
+static void verifySystemIdmaps()
+{
+    pid_t pid;
+    char system_id[10];
 
-    // child
-    case 0: {
-      struct __user_cap_header_struct capheader;
-      struct __user_cap_data_struct capdata;
+    snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
 
-      memset(&capheader, 0, sizeof(capheader));
-      memset(&capdata, 0, sizeof(capdata));
+    switch (pid = fork()) {
+        case -1:
+            ALOGE("failed to fork for idmap: %s", strerror(errno));
+            break;
+        case 0: // child
+            {
+                struct __user_cap_header_struct capheader;
+                struct __user_cap_data_struct capdata;
 
-      capheader.version = _LINUX_CAPABILITY_VERSION;
-      capheader.pid = 0;
+                memset(&capheader, 0, sizeof(capheader));
+                memset(&capdata, 0, sizeof(capdata));
 
-      if (capget(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capget";
-        exit(1);
-      }
+                capheader.version = _LINUX_CAPABILITY_VERSION;
+                capheader.pid = 0;
 
-      capdata.effective = capdata.permitted;
-      if (capset(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capset";
-        exit(1);
-      }
+                if (capget(&capheader, &capdata) != 0) {
+                    ALOGE("capget: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setgid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setgid";
-        exit(1);
-      }
+                capdata.effective = capdata.permitted;
+                if (capset(&capheader, &capdata) != 0) {
+                    ALOGE("capset: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setuid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setuid";
-        exit(1);
-      }
+                if (setgid(AID_SYSTEM) != 0) {
+                    ALOGE("setgid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      // Generic idmap parameters
-      const char* argv[8];
-      int argc = 0;
-      struct stat st;
+                if (setuid(AID_SYSTEM) != 0) {
+                    ALOGE("setuid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      memset(argv, 0, sizeof(argv));
-      argv[argc++] = AssetManager::IDMAP_BIN;
-      argv[argc++] = "--scan";
-      argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
-      argv[argc++] = AssetManager::TARGET_APK_PATH;
-      argv[argc++] = AssetManager::IDMAP_DIR;
+                // Generic idmap parameters
+                const char* argv[8];
+                int argc = 0;
+                struct stat st;
 
-      // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
-      // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
-      std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
-                                                         "");
-      if (!overlay_theme_path.empty()) {
-        overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
-        if (stat(overlay_theme_path.c_str(), &st) == 0) {
-          argv[argc++] = overlay_theme_path.c_str();
-        }
-      }
+                memset(argv, NULL, sizeof(argv));
+                argv[argc++] = AssetManager::IDMAP_BIN;
+                argv[argc++] = "--scan";
+                argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+                argv[argc++] = AssetManager::TARGET_APK_PATH;
+                argv[argc++] = AssetManager::IDMAP_DIR;
 
-      if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
-        argv[argc++] = AssetManager::OVERLAY_DIR;
-      }
+                // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
+                // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
+                char subdir[PROP_VALUE_MAX];
+                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+                if (len > 0) {
+                    String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+                    if (stat(overlayPath.string(), &st) == 0) {
+                        argv[argc++] = overlayPath.string();
+                    }
+                }
+                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::OVERLAY_DIR;
+                }
 
-      if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
-        argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
-      }
+                if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
+                }
 
-      // Finally, invoke idmap (if any overlay directory exists)
-      if (argc > 5) {
-        execv(AssetManager::IDMAP_BIN, (char* const*)argv);
-        PLOG(ERROR) << "failed to execv for idmap";
-        exit(1); // should never get here
-      } else {
-        exit(0);
-      }
-  } break;
-
-  // parent
-  default:
-    waitpid(pid, nullptr, 0);
-    break;
-  }
+                // Finally, invoke idmap (if any overlay directory exists)
+                if (argc > 5) {
+                    execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+                    ALOGE("failed to execv for idmap: %s", strerror(errno));
+                    exit(1); // should never get here
+                } else {
+                    exit(0);
+                }
+            }
+            break;
+        default: // parent
+            waitpid(pid, NULL, 0);
+            break;
+    }
 }
 
-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);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
-                   ApkAssetsCookieToJavaCookie(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));
-}
 
 // ----------------------------------------------------------------------------
 
-// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
-struct GuardedAssetManager : public ::AAssetManager {
-  Guarded<AssetManager2> guarded_assetmanager;
-};
-
-::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
-  ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
-  if (am == nullptr) {
+// this guy is exported to other jni routines
+AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
+{
+    jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
+    AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
+    if (am != NULL) {
+        return am;
+    }
     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
-    return nullptr;
-  }
-  return am;
+    return NULL;
 }
 
-Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
-  if (assetmanager == nullptr) {
-    return nullptr;
-  }
-  return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
-}
-
-Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
-}
-
-static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
-  return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
-}
-
-static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
-                                          jlongArray out_offsets) {
-  off64_t start_offset, length;
-  int fd = asset->openFileDescriptor(&start_offset, &length);
-  asset.reset();
-
-  if (fd < 0) {
-    jniThrowException(env, "java/io/FileNotFoundException",
-                      "This file can not be opened as a file descriptor; it is probably "
-                      "compressed");
-    return nullptr;
-  }
-
-  jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
-  if (offsets == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-
-  offsets[0] = start_offset;
-  offsets[1] = length;
-
-  env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
-
-  jobject file_desc = jniCreateFileDescriptor(env, fd);
-  if (file_desc == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-  return newParcelFileDescriptor(env, file_desc);
-}
-
-static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  return Asset::getGlobalCount();
-}
-
-static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
-  String8 alloc = Asset::getAssetAllocations();
-  if (alloc.length() <= 0) {
-    return nullptr;
-  }
-  return env->NewStringUTF(alloc.string());
-}
-
-static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  // TODO(adamlesinski): Switch to AssetManager2.
-  return AssetManager::getGlobalCount();
-}
-
-static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
-  // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
-  // AssetManager2 in a contiguous block (GuardedAssetManager).
-  return reinterpret_cast<jlong>(new GuardedAssetManager());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  delete reinterpret_cast<GuardedAssetManager*>(ptr);
-}
-
-static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                               jobjectArray apk_assets_array, jboolean invalidate_caches) {
-  const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
-  std::vector<const ApkAssets*> apk_assets;
-  apk_assets.reserve(apk_assets_len);
-  for (jsize i = 0; i < apk_assets_len; i++) {
-    jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
-    if (obj == nullptr) {
-      std::string msg = StringPrintf("ApkAssets at index %d is null", i);
-      jniThrowNullPointerException(env, msg.c_str());
-      return;
+static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
-    if (env->ExceptionCheck()) {
-      return;
-    }
-    apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
-  }
+    ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetApkAssets(apk_assets, invalidate_caches);
-}
-
-static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
-                                   jstring locale, jint orientation, jint touchscreen, jint density,
-                                   jint keyboard, jint keyboard_hidden, jint navigation,
-                                   jint screen_width, jint screen_height,
-                                   jint smallest_screen_width_dp, jint screen_width_dp,
-                                   jint screen_height_dp, jint screen_layout, jint ui_mode,
-                                   jint color_mode, jint major_version) {
-  ResTable_config configuration;
-  memset(&configuration, 0, sizeof(configuration));
-  configuration.mcc = static_cast<uint16_t>(mcc);
-  configuration.mnc = static_cast<uint16_t>(mnc);
-  configuration.orientation = static_cast<uint8_t>(orientation);
-  configuration.touchscreen = static_cast<uint8_t>(touchscreen);
-  configuration.density = static_cast<uint16_t>(density);
-  configuration.keyboard = static_cast<uint8_t>(keyboard);
-  configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
-  configuration.navigation = static_cast<uint8_t>(navigation);
-  configuration.screenWidth = static_cast<uint16_t>(screen_width);
-  configuration.screenHeight = static_cast<uint16_t>(screen_height);
-  configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
-  configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
-  configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
-  configuration.screenLayout = static_cast<uint8_t>(screen_layout);
-  configuration.uiMode = static_cast<uint8_t>(ui_mode);
-  configuration.colorMode = static_cast<uint8_t>(color_mode);
-  configuration.sdkVersion = static_cast<uint16_t>(major_version);
-
-  if (locale != nullptr) {
-    ScopedUtfChars locale_utf8(env, locale);
-    CHECK(locale_utf8.c_str() != nullptr);
-    configuration.setBcp47Locale(locale_utf8.c_str());
-  }
-
-  // Constants duplicated from Java class android.content.res.Configuration.
-  static const jint kScreenLayoutRoundMask = 0x300;
-  static const jint kScreenLayoutRoundShift = 8;
-
-  // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
-  // in C++. We must extract the round qualifier out of the Java screenLayout and put it
-  // into screenLayout2.
-  configuration.screenLayout2 =
-      static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetConfiguration(configuration);
-}
-
-static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-
-  jobject sparse_array =
-        env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
-
-  if (sparse_array == nullptr) {
-    // An exception is pending.
-    return nullptr;
-  }
-
-  assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
-    jstring jpackage_name = env->NewStringUTF(package_name.c_str());
-    if (jpackage_name == nullptr) {
-      // An exception is pending.
-      return;
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
+        return -1;
     }
 
-    env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
-                        jpackage_name);
-  });
-  return sparse_array;
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
+    }
+
+    Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return reinterpret_cast<jlong>(a);
 }
 
-static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
-  ScopedUtfChars path_utf8(env, path);
-  if (path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
+static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
+{
+    off64_t startOffset, length;
+    int fd = a->openFileDescriptor(&startOffset, &length);
+    delete a;
 
-  std::vector<std::string> all_file_paths;
-  {
-    StringPiece normalized_path = path_utf8.c_str();
-    if (normalized_path.data()[0] == '/') {
-      normalized_path = normalized_path.substr(1);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/FileNotFoundException",
+                "This file can not be opened as a file descriptor; it is probably compressed");
+        return NULL;
     }
-    std::string root_path = StringPrintf("assets/%s", normalized_path.data());
-    ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-    for (const ApkAssets* assets : assetmanager->GetApkAssets()) {
-      assets->ForEachFile(root_path, [&](const StringPiece& file_path, FileType type) {
-        if (type == FileType::kFileTypeRegular) {
-          all_file_paths.push_back(file_path.to_string());
+
+    jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
+    if (offsets == NULL) {
+        close(fd);
+        return NULL;
+    }
+
+    offsets[0] = startOffset;
+    offsets[1] = length;
+
+    env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
+
+    jobject fileDesc = jniCreateFileDescriptor(env, fd);
+    if (fileDesc == NULL) {
+        close(fd);
+        return NULL;
+    }
+
+    return newParcelFileDescriptor(env, fileDesc);
+}
+
+static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return -1;
+    }
+
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
+    }
+
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
+                (Asset::AccessMode)mode)
+        : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return reinterpret_cast<jlong>(a);
+}
+
+static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
+                                                   jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    AssetDir* dir = am->openDir(fileName8.c_str());
+
+    if (dir == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    size_t N = dir->getFileCount();
+
+    jobjectArray array = env->NewObjectArray(dir->getFileCount(),
+                                                g_stringClass, NULL);
+    if (array == NULL) {
+        delete dir;
+        return NULL;
+    }
+
+    for (size_t i=0; i<N; i++) {
+        const String8& name = dir->getFileName(i);
+        jstring str = env->NewStringUTF(name.string());
+        if (str == NULL) {
+            delete dir;
+            return NULL;
         }
-      });
-    }
-  }
-
-  jobjectArray array = env->NewObjectArray(all_file_paths.size(), g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jsize index = 0;
-  for (const std::string& file_path : all_file_paths) {
-    jstring java_string = env->NewStringUTF(file_path.c_str());
-
-    // Check for errors creating the strings (if malformed or no memory).
-    if (env->ExceptionCheck()) {
-     return nullptr;
+        env->SetObjectArrayElement(array, i, str);
+        env->DeleteLocalRef(str);
     }
 
-    env->SetObjectArrayElement(array, index++, java_string);
+    delete dir;
 
-    // If we have a large amount of string in our array, we might overflow the
-    // local reference table of the VM.
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
+    return array;
 }
 
-static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                             jint access_mode) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
+static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
+    //printf("Destroying Asset Stream: %p\n", a);
 
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset =
-      assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                                 jlongArray out_offsets) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path, jint access_mode) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
-                                       static_cast<Asset::AccessMode>(access_mode));
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
-                                       static_cast<Asset::AccessMode>(access_mode));
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                    jstring asset_path, jlongArray out_offsets) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-
-  // May be nullptr.
-  const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
-
-  std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
-  status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
-  asset.reset();
-
-  if (err != NO_ERROR) {
-    jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
-    return 0;
-  }
-  return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                   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) {
-    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) {
-      return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-    }
-  }
-  return CopyValue(env, cookie, value, ref, flags, &selected_config, 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) {
-    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).
-    }
-  }
-
-  if (cookie == kInvalidCookie) {
-    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) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-  return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, 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) {
-    return nullptr;
-  }
-
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (env->ExceptionCheck()) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < bag->entry_count; i++) {
-    jint attr_resid = bag->entries[i].key;
-    env->SetIntArrayRegion(array, i, 1, &attr_resid);
-  }
-  return array;
-}
-
-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) {
-    return nullptr;
-  }
-
-  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) {
-      return nullptr;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return;
     }
 
-    if (value.dataType == Res_value::TYPE_STRING) {
-      const ApkAssets* apk_assets = assetmanager->GetApkAssets()[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);
-      } else {
-        const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
-        java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
-      }
-
-      // Check for errors creating the strings (if malformed or no memory).
-      if (env->ExceptionCheck()) {
-        return nullptr;
-      }
-
-      env->SetObjectArrayElement(array, i, java_string);
-
-      // If we have a large amount of string in our array, we might overflow the
-      // local reference table of the VM.
-      env->DeleteLocalRef(java_string);
-    }
-  }
-  return array;
+    delete a;
 }
 
-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) {
-    return nullptr;
-  }
+static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
+                                                       jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  jintArray array = env->NewIntArray(bag->entry_count * 2);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  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);
-      return nullptr;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    jint string_index = -1;
-    if (value.dataType == Res_value::TYPE_STRING) {
-      string_index = static_cast<jint>(value.data);
-    }
-
-    buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
-    buffer[(i * 2) + 1] = string_index;
-  }
-  env->ReleasePrimitiveArrayCritical(array, buffer, 0);
-  return array;
+    uint8_t b;
+    ssize_t res = a->read(&b, 1);
+    return res == 1 ? b : -1;
 }
 
-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) {
-    return nullptr;
-  }
+static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
+                                                jlong assetHandle, jbyteArray bArray,
+                                                jint off, jint len)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  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);
-      return nullptr;
+    if (a == NULL || bArray == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
-      buffer[i] = static_cast<jint>(value.data);
+    if (len == 0) {
+        return 0;
     }
-  }
-  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) {
+    jsize bLen = env->GetArrayLength(bArray);
+    if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
+        return -1;
+    }
+
+    jbyte* b = env->GetByteArrayElements(bArray, NULL);
+    ssize_t res = a->read(b+off, len);
+    env->ReleaseByteArrayElements(bArray, b, 0);
+
+    if (res > 0) return static_cast<jint>(res);
+
+    if (res < 0) {
+        jniThrowException(env, "java/io/IOException", "");
+    }
     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) {
-    return -1;
-  }
+static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
+                                                 jlong assetHandle,
+                                                 jlong offset, jint whence)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  const jsize out_data_length = env->GetArrayLength(out_data);
-  if (env->ExceptionCheck()) {
-    return -1;
-  }
-
-  if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
-    return -1;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
-  if (buffer == nullptr) {
-    return -1;
-  }
-
-  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;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
-      return -1;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        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;
+    return a->seek(
+        offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
+}
+
+static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    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_NUM_ENTRIES;
-  }
-  env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
-  return static_cast<jint>(bag->entry_count);
+    return a->getLength();
 }
 
-static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
-                                        jstring def_type, jstring def_package) {
-  ScopedUtfChars name_utf8(env, name);
-  if (name_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
+static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
+                                                               jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  std::string type;
-  if (def_type != nullptr) {
-    ScopedUtfChars type_utf8(env, def_type);
-    CHECK(type_utf8.c_str() != nullptr);
-    type = type_utf8.c_str();
-  }
-
-  std::string package;
-  if (def_package != nullptr) {
-    ScopedUtfChars package_utf8(env, def_package);
-    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));
-}
-
-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)) {
-    return nullptr;
-  }
-
-  std::string result;
-  if (name.package != nullptr) {
-    result.append(name.package, name.package_len);
-  }
-
-  if (name.type != nullptr || name.type16 != nullptr) {
-    if (!result.empty()) {
-      result += ":";
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    if (name.type != nullptr) {
-      result.append(name.type, name.type_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
-    }
-  }
+    return a->getRemainingLength();
+}
 
-  if (name.entry != nullptr || name.entry16 != nullptr) {
-    if (!result.empty()) {
-      result += "/";
+static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
+                                                       jstring path, jboolean appAsLib)
+{
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return 0;
     }
 
-    if (name.entry != nullptr) {
-      result.append(name.entry, name.entry_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
-    }
-  }
-  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)) {
-    return nullptr;
-  }
-
-  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)) {
-    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);
-  }
-  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)) {
-    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);
-  }
-  return nullptr;
-}
-
-static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
-                                     jboolean exclude_system) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::set<std::string> locales =
-      assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
-
-  jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const std::string& locale : locales) {
-    jstring java_string = env->NewStringUTF(locale.c_str());
-    if (java_string == nullptr) {
-      return nullptr;
-    }
-    env->SetObjectArrayElement(array, idx++, java_string);
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
-}
-
-static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
-  jobject result =
-      env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
-  if (result == nullptr) {
-    return nullptr;
-  }
-
-  env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
-                   config.smallestScreenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
-  return result;
-}
-
-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*/);
-
-  jobjectArray array =
-      env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const ResTable_config& configuration : configurations) {
-    jobject java_configuration = ConstructConfigurationObject(env, configuration);
-    if (java_configuration == nullptr) {
-      return nullptr;
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    env->SetObjectArrayElement(array, idx++, java_configuration);
-    env->DeleteLocalRef(java_configuration);
-  }
-  return array;
+    int32_t cookie;
+    bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
 }
 
-static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                             jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
-                             jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
+static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
+                                                     jstring idmapPath)
+{
+    ScopedUtfChars idmapPath8(env, idmapPath);
+    if (idmapPath8.c_str() == NULL) {
+        return 0;
+    }
 
-  ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-  uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
-  uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
 
-  jsize attrs_len = env->GetArrayLength(java_attrs);
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return;
-  }
+    int32_t cookie;
+    bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
 
-  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);
+    return (res) ? (jint)cookie : 0;
 }
 
-static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                   jint def_style_attr, jint def_style_resid, jintArray java_values,
-                                   jintArray java_attrs, jintArray out_java_values,
-                                   jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
+static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
+                                                    jobject fileDescriptor, jstring debugPathName,
+                                                    jboolean appAsLib)
+{
+    ScopedUtfChars debugPathName8(env, debugPathName);
 
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* values = nullptr;
-  jsize values_len = 0;
-  if (java_values != nullptr) {
-    values_len = env->GetArrayLength(java_values);
-    values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
-    if (values == nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-      return JNI_FALSE;
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+        return 0;
     }
-  }
 
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    if (values != nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
-    return JNI_FALSE;
-  }
 
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        if (values != nullptr) {
-          env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    int dupfd = ::dup(fd);
+    if (dupfd < 0) {
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
+}
+
+static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_TRUE;
+    }
+    return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
+}
+
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
+{
+    Vector<String8> locales;
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    am->getLocales(&locales, includeSystemLocales);
+
+    const int N = locales.size();
+
+    jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jstring str = env->NewStringUTF(locales[i].string());
+        if (str == NULL) {
+            return NULL;
         }
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+        env->SetObjectArrayElement(result, i, str);
+        env->DeleteLocalRef(str);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, false /* don't include system locales */);
+}
+
+static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
+    jobject result = env->NewObject(gConfigurationOffsets.classObject,
+            gConfigurationOffsets.constructor);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
+            config.smallestScreenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
+
+    return result;
+}
+
+static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
+        const Vector<ResTable_config>& configs) {
+    const int N = configs.size();
+    jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jobject config = constructConfigurationObject(env, configs[i]);
+        if (config == NULL) {
+            env->DeleteLocalRef(result);
+            return NULL;
+        }
+
+        env->SetObjectArrayElement(result, i, config);
+        env->DeleteLocalRef(config);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    const ResTable& res(am->getResources());
+    Vector<ResTable_config> configs;
+    res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
+
+    return getSizeConfigurationsInternal(env, configs);
+}
+
+static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
+                                                          jint mcc, jint mnc,
+                                                          jstring locale, jint orientation,
+                                                          jint touchscreen, jint density,
+                                                          jint keyboard, jint keyboardHidden,
+                                                          jint navigation,
+                                                          jint screenWidth, jint screenHeight,
+                                                          jint smallestScreenWidthDp,
+                                                          jint screenWidthDp, jint screenHeightDp,
+                                                          jint screenLayout, jint uiMode,
+                                                          jint colorMode, jint sdkVersion)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return;
+    }
+
+    ResTable_config config;
+    memset(&config, 0, sizeof(config));
+
+    const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
+
+    // Constants duplicated from Java class android.content.res.Configuration.
+    static const jint kScreenLayoutRoundMask = 0x300;
+    static const jint kScreenLayoutRoundShift = 8;
+
+    config.mcc = (uint16_t)mcc;
+    config.mnc = (uint16_t)mnc;
+    config.orientation = (uint8_t)orientation;
+    config.touchscreen = (uint8_t)touchscreen;
+    config.density = (uint16_t)density;
+    config.keyboard = (uint8_t)keyboard;
+    config.inputFlags = (uint8_t)keyboardHidden;
+    config.navigation = (uint8_t)navigation;
+    config.screenWidth = (uint16_t)screenWidth;
+    config.screenHeight = (uint16_t)screenHeight;
+    config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
+    config.screenWidthDp = (uint16_t)screenWidthDp;
+    config.screenHeightDp = (uint16_t)screenHeightDp;
+    config.screenLayout = (uint8_t)screenLayout;
+    config.uiMode = (uint8_t)uiMode;
+    config.colorMode = (uint8_t)colorMode;
+    config.sdkVersion = (uint16_t)sdkVersion;
+    config.minorVersion = 0;
+
+    // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+    // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+    // into screenLayout2.
+    config.screenLayout2 =
+            (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+    am->setConfiguration(config, locale8);
+
+    if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
+}
+
+static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
+                                                            jstring name,
+                                                            jstring defType,
+                                                            jstring defPackage)
+{
+    ScopedStringChars name16(env, name);
+    if (name16.get() == NULL) {
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
+        : NULL;
+    jsize defTypeLen = defType
+        ? env->GetStringLength(defType) : 0;
+    const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
+                                                                NULL))
+        : NULL;
+    jsize defPackageLen = defPackage
+        ? env->GetStringLength(defPackage) : 0;
+
+    jint ident = am->getResources().identifierForName(
+        reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
+        defType16, defTypeLen, defPackage16, defPackageLen);
+
+    if (defPackage16) {
+        env->ReleaseStringChars(defPackage,
+                                reinterpret_cast<const jchar*>(defPackage16));
+    }
+    if (defType16) {
+        env->ReleaseStringChars(defType,
+                                reinterpret_cast<const jchar*>(defType16));
+    }
+
+    return ident;
+}
+
+static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
+                                                            jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    String16 str;
+    if (name.package != NULL) {
+        str.setTo(name.package, name.packageLen);
+    }
+    if (name.type8 != NULL || name.type != NULL) {
+        if (str.size() > 0) {
+            char16_t div = ':';
+            str.append(&div, 1);
+        }
+        if (name.type8 != NULL) {
+            str.append(String16(name.type8, name.typeLen));
+        } else {
+            str.append(name.type, name.typeLen);
+        }
+    }
+    if (name.name8 != NULL || name.name != NULL) {
+        if (str.size() > 0) {
+            char16_t div = '/';
+            str.append(&div, 1);
+        }
+        if (name.name8 != NULL) {
+            str.append(String16(name.name8, name.nameLen));
+        } else {
+            str.append(name.name, name.nameLen);
+        }
+    }
+
+    return env->NewString((const jchar*)str.string(), str.size());
+}
+
+static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
+                                                                   jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.package != NULL) {
+        return env->NewString((const jchar*)name.package, name.packageLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
+                                                                jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.type8 != NULL) {
+        return env->NewStringUTF(name.type8);
+    }
+
+    if (name.type != NULL) {
+        return env->NewString((const jchar*)name.type, name.typeLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
+                                                                 jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.name8 != NULL) {
+        return env->NewStringUTF(name.name8);
+    }
+
+    if (name.name != NULL) {
+        return env->NewString((const jchar*)name.name, name.nameLen);
+    }
+
+    return NULL;
+}
+
+static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
+                                                           jint ident,
+                                                           jshort density,
+                                                           jobject outValue,
+                                                           jboolean resolve)
+{
+    if (outValue == NULL) {
+         jniThrowNullPointerException(env, "outValue");
+         return 0;
+    }
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    Res_value value;
+    ResTable_config config;
+    uint32_t typeSpecFlags;
+    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
+    if (kThrowOnBadId) {
+        if (block == BAD_INDEX) {
+            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+            return 0;
+        }
+    }
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
+                                                           jint ident, jint bagEntryId,
+                                                           jobject outValue, jboolean resolve)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    ssize_t block = -1;
+    Res_value value;
+
+    const ResTable::bag_entry* entry = NULL;
+    uint32_t typeSpecFlags;
+    ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
+
+    for (ssize_t i=0; i<entryCount; i++) {
+        if (((uint32_t)bagEntryId) == entry->map.name.ident) {
+            block = entry->stringBlock;
+            value = entry->map.value;
+        }
+        entry++;
+    }
+
+    res.unlock();
+
+    if (block < 0) {
+        return static_cast<jint>(block);
+    }
+
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return am->getResources().getTableCount();
+}
+
+static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
+                                                           jint block)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
+}
+
+static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
+                                                       jint cookie)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
+    if (name.length() == 0) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
+        return NULL;
+    }
+    jstring str = env->NewStringUTF(name.string());
+    return str;
+}
+
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const ResTable& res = am->getResources();
+
+    jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+            gSparseArrayOffsets.constructor);
+    const size_t N = res.getBasePackageCount();
+    for (size_t i = 0; i < N; i++) {
+        const String16 name = res.getBasePackageName(i);
+        env->CallVoidMethod(
+            sparseArray, gSparseArrayOffsets.put,
+            static_cast<jint>(res.getBasePackageId(i)),
+            env->NewString(reinterpret_cast<const jchar*>(name.string()),
+                           name.size()));
+    }
+    return sparseArray;
+}
+
+static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
+}
+
+static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
+                                                     jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    delete theme;
+}
+
+static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
+                                                         jlong themeHandle,
+                                                         jint styleRes,
+                                                         jboolean force)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->applyStyle(styleRes, force ? true : false);
+}
+
+static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
+                                                   jlong destHandle, jlong srcHandle)
+{
+    ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
+    ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
+    dest->setTo(*src);
+}
+
+static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->clear();
+}
+
+static jint android_content_AssetManager_loadThemeAttributeValue(
+    JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+
+    Res_value value;
+    // XXX value could be different in different configs!
+    uint32_t typeSpecFlags = 0;
+    ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
+    uint32_t ref = 0;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
+                                                                        jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    return theme->getChangingConfigurations();
+}
+
+static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
+                                                   jlong themeHandle, jint pri,
+                                                   jstring tag, jstring prefix)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+    (void)res;
+
+    // XXX Need to use params.
+    theme->dumpToLog();
+}
+
+static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
+                                                          jlong themeToken,
+                                                          jint defStyleAttr,
+                                                          jint defStyleRes,
+                                                          jintArray inValues,
+                                                          jintArray attrs,
+                                                          jintArray outValues,
+                                                          jintArray outIndices)
+{
+    if (themeToken == 0) {
+        jniThrowNullPointerException(env, "theme token");
         return JNI_FALSE;
-      }
     }
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  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));
-  if (out_indices != nullptr) {
-    env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
-  }
-
-  env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
-  if (values != nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
-  }
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-  return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                         jlong xml_parser_ptr, jintArray java_attrs,
-                                         jintArray out_java_values, jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
-
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    return JNI_FALSE;
-  }
-
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
         return JNI_FALSE;
-      }
     }
-  }
-
-  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));
-
-  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;
-}
-
-static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
-}
-
-static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  delete reinterpret_cast<Theme*>(theme_ptr);
-}
-
-static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                  jint resid, jboolean force) {
-  // AssetManager is accessed via the theme, so grab an explicit lock here.
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  theme->ApplyStyle(static_cast<uint32_t>(resid), force);
-
-  // TODO(adamlesinski): Consider surfacing exception when result is failure.
-  // CTS currently expects no exceptions from this method.
-  // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
-  // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
-}
-
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
-                            jlong src_theme_ptr) {
-  Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
-  Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
-  if (!dst_theme->SetTo(*src_theme)) {
-    jniThrowException(env, "java/lang/IllegalArgumentException",
-                      "Themes are from different AssetManagers");
-  }
-}
-
-static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  reinterpret_cast<Theme*>(theme_ptr)->Clear();
-}
-
-static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                         jint resid, jobject typed_value,
-                                         jboolean resolve_references) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  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) {
-    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 (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
     }
-  }
-  return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
+    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
+                               (uint32_t*) srcValues, NSV,
+                               (uint32_t*) src, NI,
+                               (uint32_t*) baseDest,
+                               (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                            jint priority, jstring tag, jstring prefix) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  (void) theme;
-  (void) priority;
-  (void) tag;
-  (void) prefix;
+static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
+        jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
+        jlong outValuesAddress, jlong outIndicesAddress) {
+    jint* attrs = env->GetIntArrayElements(attrsObj, 0);
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+    uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
+    uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
+    ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
+            reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
+    env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
 }
 
-static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
-                                                 jlong theme_ptr) {
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  return static_cast<jint>(theme->GetChangingConfigurations());
+static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
+                                                        jlong xmlParserToken,
+                                                        jintArray attrs,
+                                                        jintArray outValues,
+                                                        jintArray outIndices)
+{
+    if (xmlParserToken == 0) {
+        jniThrowNullPointerException(env, "xmlParserToken");
+        return JNI_FALSE;
+    }
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
+        return JNI_FALSE;
+    }
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    bool result = RetrieveAttributes(&res, xmlParser,
+                                     (uint32_t*) src, NI,
+                                     (uint32_t*) baseDest,
+                                     (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  delete reinterpret_cast<Asset*>(asset_ptr);
+static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
+                                                       jint id)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    res.lock();
+    const ResTable::bag_entry* defStyleEnt = NULL;
+    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
+    res.unlock();
+
+    return static_cast<jint>(bagOff);
 }
 
-static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  uint8_t b;
-  ssize_t res = asset->read(&b, sizeof(b));
-  return res == sizeof(b) ? static_cast<jint>(b) : -1;
+static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
+                                                        jint id,
+                                                        jintArray outValues)
+{
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResTable_config config;
+    Res_value value;
+    ssize_t block;
+
+    const jsize NV = env->GetArrayLength(outValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
+    if (dest == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return JNI_FALSE;
+    }
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    const ResTable::bag_entry* arrayEnt = NULL;
+    uint32_t arrayTypeSetFlags = 0;
+    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+    const ResTable::bag_entry* endArrayEnt = arrayEnt +
+        (bagOff >= 0 ? bagOff : 0);
+
+    int i = 0;
+    uint32_t typeSetFlags;
+    while (i < NV && arrayEnt < endArrayEnt) {
+        block = arrayEnt->stringBlock;
+        typeSetFlags = arrayTypeSetFlags;
+        config.density = 0;
+        value = arrayEnt->map.value;
+
+        uint32_t resid = 0;
+        if (value.dataType != Res_value::TYPE_NULL) {
+            // Take care of resolving the found resource to its final value.
+            //printf("Resolving attribute reference\n");
+            ssize_t newBlock = res.resolveReference(&value, block, &resid,
+                    &typeSetFlags, &config);
+            if (kThrowOnBadId) {
+                if (newBlock == BAD_INDEX) {
+                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                    return JNI_FALSE;
+                }
+            }
+            if (newBlock >= 0) block = newBlock;
+        }
+
+        // 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;
+        }
+
+        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+        // Write the final value back to Java.
+        dest[STYLE_TYPE] = value.dataType;
+        dest[STYLE_DATA] = value.data;
+        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
+        dest[STYLE_RESOURCE_ID] = resid;
+        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
+        dest += STYLE_NUM_ENTRIES;
+        i+= STYLE_NUM_ENTRIES;
+        arrayEnt++;
+    }
+
+    i /= STYLE_NUM_ENTRIES;
+
+    res.unlock();
+
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+
+    return i;
 }
 
-static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
-                            jint offset, jint len) {
-  if (len == 0) {
-    return 0;
-  }
+static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
 
-  jsize buffer_len = env->GetArrayLength(java_buffer);
-  if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
-      offset > buffer_len - len) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
-    return -1;
-  }
+    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedByteArrayRW byte_array(env, java_buffer);
-  if (byte_array.get() == nullptr) {
-    return -1;
-  }
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return 0;
+    }
 
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  ssize_t res = asset->read(byte_array.get() + offset, len);
-  if (res < 0) {
-    jniThrowException(env, "java/io/IOException", "");
-    return -1;
-  }
-  return res > 0 ? static_cast<jint>(res) : -1;
+    int32_t assetCookie = static_cast<int32_t>(cookie);
+    Asset* a = assetCookie
+        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return 0;
+    }
+
+    const DynamicRefTable* dynamicRefTable =
+            am->getResources().getDynamicRefTableForCookie(assetCookie);
+    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
+    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
+    a->close();
+    delete a;
+
+    if (err != NO_ERROR) {
+        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+        return 0;
+    }
+
+    return reinterpret_cast<jlong>(block);
 }
 
-static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
-                             jint whence) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->seek(
-      static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
+static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
+                                                                 jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N * 2);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
+        jint stringIndex = -1;
+        jint stringBlock = 0;
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (value.dataType == Res_value::TYPE_STRING) {
+            stringIndex = value.data;
+        }
+
+        if (kThrowOnBadId) {
+            if (stringBlock == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+
+        //todo: It might be faster to allocate a C array to contain
+        //      the blocknums and indices, put them in there and then
+        //      do just one SetIntArrayRegion()
+        env->SetIntArrayRegion(array, j, 1, &stringBlock);
+        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
+        j = j + 2;
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getLength());
+static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
+    if (env->ExceptionCheck()) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    size_t strLen = 0;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+        jstring str = NULL;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType == Res_value::TYPE_STRING) {
+            const ResStringPool* pool = res.getTableStringBlock(block);
+            const char* str8 = pool->string8At(value.data, &strLen);
+            if (str8 != NULL) {
+                str = env->NewStringUTF(str8);
+            } else {
+                const char16_t* str16 = pool->stringAt(value.data, &strLen);
+                str = env->NewString(reinterpret_cast<const jchar*>(str16),
+                                     strLen);
+            }
+
+            // If one of our NewString{UTF} calls failed due to memory, an
+            // exception will be pending.
+            if (env->ExceptionCheck()) {
+                res.unlockBag(startOfBag);
+                return NULL;
+            }
+
+            env->SetObjectArrayElement(array, i, str);
+
+            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
+            // If we have a large amount of strings in our array, we might
+            // overflow the local reference table of the VM.
+            env->DeleteLocalRef(str);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getRemainingLength());
+static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType >= Res_value::TYPE_FIRST_INT
+                && value.dataType <= Res_value::TYPE_LAST_INT) {
+            int intVal = value.data;
+            env->SetIntArrayRegion(array, i, 1, &intVal);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
+                                                                 jint styleId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(styleId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        int resourceId = bag->map.name.ident;
+        env->SetIntArrayRegion(array, i, 1, &resourceId);
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
+{
+    if (isSystem) {
+        verifySystemIdmaps();
+    }
+    AssetManager* am = new AssetManager();
+    if (am == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return;
+    }
+
+    am->addDefaultAssets();
+
+    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
+    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
+}
+
+static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = (AssetManager*)
+        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
+    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
+    if (am != NULL) {
+        delete am;
+        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
+    }
+}
+
+static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
+{
+    return Asset::getGlobalCount();
+}
+
+static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
+{
+    String8 alloc = Asset::getAssetAllocations();
+    if (alloc.length() <= 0) {
+        return NULL;
+    }
+
+    jstring str = env->NewStringUTF(alloc.string());
+    return str;
+}
+
+static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
+{
+    return AssetManager::getGlobalCount();
 }
 
 // ----------------------------------------------------------------------------
 
-// JNI registration.
+/*
+ * JNI registration.
+ */
 static const JNINativeMethod gAssetManagerMethods[] = {
-    // AssetManager setup methods.
-    {"nativeCreate", "()J", (void*)NativeCreate},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
-    {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
-     (void*)NativeSetConfiguration},
-    {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
-     (void*)NativeGetAssignedPackageIdentifiers},
+    /* name, signature, funcPtr */
 
-    // AssetManager file methods.
-    {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
-    {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
-    {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenAssetFd},
-    {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
-    {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenNonAssetFd},
-    {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
+    // Basic asset stuff.
+    { "openAsset",      "(Ljava/lang/String;I)J",
+        (void*) android_content_AssetManager_openAsset },
+    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openAssetFd },
+    { "openNonAssetNative", "(ILjava/lang/String;I)J",
+        (void*) android_content_AssetManager_openNonAssetNative },
+    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openNonAssetFdNative },
+    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_list },
+    { "destroyAsset",   "(J)V",
+        (void*) android_content_AssetManager_destroyAsset },
+    { "readAssetChar",  "(J)I",
+        (void*) android_content_AssetManager_readAssetChar },
+    { "readAsset",      "(J[BII)I",
+        (void*) android_content_AssetManager_readAsset },
+    { "seekAsset",      "(JJI)J",
+        (void*) android_content_AssetManager_seekAsset },
+    { "getAssetLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetLength },
+    { "getAssetRemainingLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetRemainingLength },
+    { "addAssetPathNative", "(Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetPath },
+    { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetFd },
+    { "addOverlayPathNative",   "(Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_addOverlayPath },
+    { "isUpToDate",     "()Z",
+        (void*) android_content_AssetManager_isUpToDate },
 
-    // AssetManager resource methods.
-    {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
-    {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
-     (void*)NativeGetResourceBagValue},
-    {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
-    {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
-     (void*)NativeGetResourceStringArray},
-    {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
-    {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
-    {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
-    {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
+    // Resources.
+    { "getLocales",      "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getLocales },
+    { "getNonSystemLocales", "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getNonSystemLocales },
+    { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
+        (void*) android_content_AssetManager_getSizeConfigurations },
+    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
+        (void*) android_content_AssetManager_setConfiguration },
+    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_getResourceIdentifier },
+    { "getResourceName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceName },
+    { "getResourcePackageName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourcePackageName },
+    { "getResourceTypeName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceTypeName },
+    { "getResourceEntryName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceEntryName },
+    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceValue },
+    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceBagValue },
+    { "getStringBlockCount","()I",
+        (void*) android_content_AssetManager_getStringBlockCount },
+    { "getNativeStringBlock","(I)J",
+        (void*) android_content_AssetManager_getNativeStringBlock },
+    { "getCookieName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getCookieName },
+    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
 
-    // AssetManager resource name/ID methods.
-    {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
-     (void*)NativeGetResourceIdentifier},
-    {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
-    {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
-    {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
-    {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
-    {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
-    {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
-     (void*)NativeGetSizeConfigurations},
+    // Themes.
+    { "newTheme", "()J",
+        (void*) android_content_AssetManager_newTheme },
+    { "deleteTheme", "(J)V",
+        (void*) android_content_AssetManager_deleteTheme },
+    { "applyThemeStyle", "(JIZ)V",
+        (void*) android_content_AssetManager_applyThemeStyle },
+    { "copyTheme", "(JJ)V",
+        (void*) android_content_AssetManager_copyTheme },
+    { "clearTheme", "(J)V",
+        (void*) android_content_AssetManager_clearTheme },
+    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadThemeAttributeValue },
+    { "getThemeChangingConfigurations", "(J)I",
+        (void*) android_content_AssetManager_getThemeChangingConfigurations },
+    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
+        (void*) android_content_AssetManager_dumpTheme },
+    { "applyStyle","(JIIJ[IIJJ)V",
+        (void*) android_content_AssetManager_applyStyle },
+    { "resolveAttrs","(JII[I[I[I[I)Z",
+        (void*) android_content_AssetManager_resolveAttrs },
+    { "retrieveAttributes","(J[I[I[I)Z",
+        (void*) android_content_AssetManager_retrieveAttributes },
+    { "getArraySize","(I)I",
+        (void*) android_content_AssetManager_getArraySize },
+    { "retrieveArray","(I[I)I",
+        (void*) android_content_AssetManager_retrieveArray },
 
-    // Style attribute related methods.
-    {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
-    {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
-    {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
+    // XML files.
+    { "openXmlAssetNative", "(ILjava/lang/String;)J",
+        (void*) android_content_AssetManager_openXmlAssetNative },
 
-    // Theme related methods.
-    {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
-    {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
-    {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
-    {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
-    {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
-    {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
-     (void*)NativeThemeGetAttributeValue},
-    {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
-    {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
+    // Arrays.
+    { "getArrayStringResource","(I)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getArrayStringResource },
+    { "getArrayStringInfo","(I)[I",
+        (void*) android_content_AssetManager_getArrayStringInfo },
+    { "getArrayIntResource","(I)[I",
+        (void*) android_content_AssetManager_getArrayIntResource },
+    { "getStyleAttributes","(I)[I",
+        (void*) android_content_AssetManager_getStyleAttributes },
 
-    // AssetInputStream methods.
-    {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
-    {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
-    {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
-    {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
-    {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
-    {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
-
-    // System/idmap related methods.
-    {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
-
-    // Global management/debug methods.
-    {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
-    {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
-    {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+    // Bookkeeping.
+    { "init",           "(Z)V",
+        (void*) android_content_AssetManager_init },
+    { "destroy",        "()V",
+        (void*) android_content_AssetManager_destroy },
+    { "getGlobalAssetCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetCount },
+    { "getAssetAllocations", "()Ljava/lang/String;",
+        (void*) android_content_AssetManager_getAssetAllocations },
+    { "getGlobalAssetManagerCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
 };
 
-int register_android_content_AssetManager(JNIEnv* env) {
-  jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
-  gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
+int register_android_content_AssetManager(JNIEnv* env)
+{
+    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
+                                                 "Ljava/lang/CharSequence;");
+    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
+                                                                 "changingConfigurations", "I");
+    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
 
-  jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
-  gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
-  gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
-  gTypedValueOffsets.mString =
-      GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
-  gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
-  gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
-  gTypedValueOffsets.mChangingConfigurations =
-      GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
-  gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
+                                                      "Landroid/os/ParcelFileDescriptor;");
+    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
 
-  jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
-  gAssetFileDescriptorOffsets.mFd =
-      GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
-  gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
-  gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
 
-  jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
-  gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+    jclass stringClass = FindClassOrDie(env, "java/lang/String");
+    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
 
-  jclass stringClass = FindClassOrDie(env, "java/lang/String");
-  g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
+                                                       "<init>", "()V");
+    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
+                                               "(ILjava/lang/Object;)V");
 
-  jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
-  gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
-  gSparseArrayOffsets.constructor =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
-  gSparseArrayOffsets.put =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+    jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
+    gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
+    gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
+            "<init>", "()V");
+    gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "smallestScreenWidthDp", "I");
+    gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenWidthDp", "I");
+    gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenHeightDp", "I");
 
-  jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
-  gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
-  gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
-  gConfigurationOffsets.mSmallestScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
-  gConfigurationOffsets.mScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
-  gConfigurationOffsets.mScreenHeightDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
-
-  return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
-                              NELEM(gAssetManagerMethods));
+    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+                                NELEM(gAssetManagerMethods));
 }
 
 }; // namespace android