Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 // transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_util_AssetManager.cpp
      4 
      5 import static android.os.Build.VERSION_CODES.P;
      6 import static android.os.Build.VERSION_CODES.Q;
      7 import static org.robolectric.res.android.ApkAssetsCookie.K_INVALID_COOKIE;
      8 import static org.robolectric.res.android.ApkAssetsCookie.kInvalidCookie;
      9 import static org.robolectric.res.android.Asset.SEEK_CUR;
     10 import static org.robolectric.res.android.Asset.SEEK_END;
     11 import static org.robolectric.res.android.Asset.SEEK_SET;
     12 import static org.robolectric.res.android.AttributeResolution9.ApplyStyle;
     13 import static org.robolectric.res.android.AttributeResolution9.ResolveAttrs;
     14 import static org.robolectric.res.android.AttributeResolution9.RetrieveAttributes;
     15 import static org.robolectric.res.android.Errors.NO_ERROR;
     16 import static org.robolectric.res.android.Util.ATRACE_NAME;
     17 import static org.robolectric.res.android.Util.CHECK;
     18 import static org.robolectric.res.android.Util.JNI_FALSE;
     19 import static org.robolectric.res.android.Util.JNI_TRUE;
     20 import static org.robolectric.res.android.Util.isTruthy;
     21 import static org.robolectric.shadow.api.Shadow.directlyOn;
     22 import static org.robolectric.shadow.api.Shadow.invokeConstructor;
     23 import static org.robolectric.res.android.Registries.NATIVE_RES_XML_PARSERS;
     24 import static org.robolectric.res.android.Registries.NATIVE_RES_XML_TREES;
     25 
     26 import android.annotation.AnyRes;
     27 import android.annotation.ArrayRes;
     28 import android.annotation.AttrRes;
     29 import android.annotation.NonNull;
     30 import android.annotation.Nullable;
     31 import android.annotation.StyleRes;
     32 import android.content.res.ApkAssets;
     33 import android.content.res.AssetManager;
     34 import android.content.res.Configuration;
     35 import android.content.res.Configuration.NativeConfig;
     36 import android.os.Build;
     37 import android.os.ParcelFileDescriptor;
     38 import android.util.ArraySet;
     39 import android.util.SparseArray;
     40 import android.util.TypedValue;
     41 import dalvik.system.VMRuntime;
     42 import java.io.File;
     43 import java.io.FileDescriptor;
     44 import java.io.FileNotFoundException;
     45 import java.io.IOException;
     46 import java.util.ArrayList;
     47 import java.util.Collection;
     48 import java.util.List;
     49 import java.util.Set;
     50 import org.robolectric.RuntimeEnvironment;
     51 import org.robolectric.annotation.Implementation;
     52 import org.robolectric.annotation.Implements;
     53 import org.robolectric.annotation.RealObject;
     54 import org.robolectric.annotation.Resetter;
     55 import org.robolectric.res.Fs;
     56 import org.robolectric.res.FsFile;
     57 import org.robolectric.res.android.CppApkAssets;
     58 import org.robolectric.res.android.ApkAssetsCookie;
     59 import org.robolectric.res.android.Asset;
     60 import org.robolectric.res.android.AssetDir;
     61 import org.robolectric.res.android.AssetPath;
     62 import org.robolectric.res.android.CppAssetManager;
     63 import org.robolectric.res.android.CppAssetManager2;
     64 import org.robolectric.res.android.CppAssetManager2.ResolvedBag;
     65 import org.robolectric.res.android.CppAssetManager2.ResourceName;
     66 import org.robolectric.res.android.CppAssetManager2.Theme;
     67 import org.robolectric.res.android.DynamicRefTable;
     68 import org.robolectric.res.android.Ref;
     69 import org.robolectric.res.android.Registries;
     70 import org.robolectric.res.android.ResStringPool;
     71 import org.robolectric.res.android.ResTable_config;
     72 import org.robolectric.res.android.ResXMLParser;
     73 import org.robolectric.res.android.ResXMLTree;
     74 import org.robolectric.res.android.ResourceTypes.Res_value;
     75 import org.robolectric.shadow.api.Shadow;
     76 import org.robolectric.util.ReflectionHelpers;
     77 import org.robolectric.util.ReflectionHelpers.ClassParameter;
     78 
     79 @Implements(value = AssetManager.class, minSdk = Build.VERSION_CODES.P,
     80     shadowPicker = ShadowAssetManager.Picker.class)
     81 public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase {
     82 
     83   private static final int STYLE_NUM_ENTRIES = 6;
     84   private static final int STYLE_TYPE = 0;
     85   private static final int STYLE_DATA = 1;
     86   private static final int STYLE_ASSET_COOKIE = 2;
     87   private static final int STYLE_RESOURCE_ID = 3;
     88   private static final int STYLE_CHANGING_CONFIGURATIONS = 4;
     89   private static final int STYLE_DENSITY = 5;
     90 
     91   private static CppAssetManager2 systemCppAssetManager2;
     92   private static long systemCppAssetManager2Ref;
     93   private static boolean inNonSystemConstructor;
     94   private static ApkAssets[] cachedSystemApkAssets;
     95   private static ArraySet<ApkAssets> cachedSystemApkAssetsSet;
     96 
     97   @RealObject AssetManager realAssetManager;
     98 
     99 //  @RealObject
    100 //  protected AssetManager realObject;
    101 
    102   // #define ATRACE_TAG ATRACE_TAG_RESOURCES
    103 // #define LOG_TAG "asset"
    104 //
    105 // #include <inttypes.h>
    106 // #include <linux/capability.h>
    107 // #include <stdio.h>
    108 // #include <sys/stat.h>
    109 // #include <sys/system_properties.h>
    110 // #include <sys/types.h>
    111 // #include <sys/wait.h>
    112 //
    113 // #include <private/android_filesystem_config.h> // for AID_SYSTEM
    114 //
    115 // #include "android-base/logging.h"
    116 // #include "android-base/properties.h"
    117 // #include "android-base/stringprintf.h"
    118 // #include "android_runtime/android_util_AssetManager.h"
    119 // #include "android_runtime/AndroidRuntime.h"
    120 // #include "android_util_Binder.h"
    121 // #include "androidfw/Asset.h"
    122 // #include "androidfw/AssetManager.h"
    123 // #include "androidfw/AssetManager2.h"
    124 // #include "androidfw/AttributeResolution.h"
    125 // #include "androidfw/MutexGuard.h"
    126 // #include "androidfw/ResourceTypes.h"
    127 // #include "core_jni_helpers.h"
    128 // #include "jni.h"
    129 // #include "nativehelper/JNIHelp.h"
    130 // #include "nativehelper/ScopedPrimitiveArray.h"
    131 // #include "nativehelper/ScopedStringChars.h"
    132 // #include "nativehelper/String.h"
    133 // #include "utils/Log.h"
    134 // #include "utils/misc.h"
    135 // #include "utils/String.h"
    136 // #include "utils/Trace.h"
    137 //
    138 // extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
    139 // extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
    140 //
    141 // using ::android::base::StringPrintf;
    142 //
    143 // namespace android {
    144 //
    145 // // ----------------------------------------------------------------------------
    146 //
    147 
    148 // static class typedvalue_offsets_t {
    149 //   jfieldID mType;
    150 //   jfieldID mData;
    151 //   jfieldID mString;
    152 //   jfieldID mAssetCookie;
    153 //   jfieldID mResourceId;
    154 //   jfieldID mChangingConfigurations;
    155 //   jfieldID mDensity;
    156 // }
    157 // static final typedvalue_offsets_t gTypedValueOffsets = new typedvalue_offsets_t();
    158 //
    159 // static class assetfiledescriptor_offsets_t {
    160 //   jfieldID mFd;
    161 //   jfieldID mStartOffset;
    162 //   jfieldID mLength;
    163 // }
    164 // static final assetfiledescriptor_offsets_t gAssetFileDescriptorOffsets = new assetfiledescriptor_offsets_t();
    165 //
    166 // static class assetmanager_offsets_t
    167 // {
    168 //   jfieldID mObject;
    169 // };
    170 // // This is also used by asset_manager.cpp.
    171 // static final assetmanager_offsets_t gAssetManagerOffsets = new assetmanager_offsets_t();
    172 //
    173 // static class apkassetsfields {
    174 //   jfieldID native_ptr;
    175 // }
    176 // static final apkassetsfields gApkAssetsFields = new apkassetsfields();
    177 //
    178 // static class sparsearray_offsets_t {
    179 //   jclass classObject;
    180 //   jmethodID constructor;
    181 //   jmethodID put;
    182 // }
    183 // static final sparsearray_offsets_t gSparseArrayOffsets = new sparsearray_offsets_t();
    184 //
    185 // static class configuration_offsets_t {
    186 //   jclass classObject;
    187 //   jmethodID constructor;
    188 //   jfieldID mSmallestScreenWidthDpOffset;
    189 //   jfieldID mScreenWidthDpOffset;
    190 //   jfieldID mScreenHeightDpOffset;
    191 // }
    192 // static final configuration_offsets_t gConfigurationOffsets = new configuration_offsets_t();
    193 //
    194 // jclass g_stringClass = nullptr;
    195 //
    196 // // ----------------------------------------------------------------------------
    197 
    198   @Implementation
    199   protected static void createSystemAssetsInZygoteLocked() {
    200     AssetManager sSystem = ReflectionHelpers.getStaticField(AssetManager.class, "sSystem");
    201     if (sSystem != null) {
    202       return;
    203     }
    204 
    205     if (systemCppAssetManager2 == null) {
    206       // first time! let the framework create a CppAssetManager2 and an AssetManager, which we'll
    207       // hang on to.
    208       directlyOn(AssetManager.class, "createSystemAssetsInZygoteLocked");
    209       cachedSystemApkAssets =
    210           ReflectionHelpers.getStaticField(AssetManager.class, "sSystemApkAssets");
    211       cachedSystemApkAssetsSet =
    212           ReflectionHelpers.getStaticField(AssetManager.class, "sSystemApkAssetsSet");
    213     } else {
    214       // reuse the shared system CppAssetManager2; create a new AssetManager around it.
    215       ReflectionHelpers.setStaticField(AssetManager.class, "sSystemApkAssets",
    216           cachedSystemApkAssets);
    217       ReflectionHelpers.setStaticField(AssetManager.class, "sSystemApkAssetsSet",
    218           cachedSystemApkAssetsSet);
    219 
    220       sSystem = ReflectionHelpers.callConstructor(AssetManager.class,
    221           ClassParameter.from(boolean.class, true /*sentinel*/));
    222       sSystem.setApkAssets(cachedSystemApkAssets, false /*invalidateCaches*/);
    223       ReflectionHelpers.setStaticField(AssetManager.class, "sSystem", sSystem);
    224     }
    225   }
    226 
    227   @Resetter
    228   public static void reset() {
    229     // todo: ShadowPicker doesn't discriminate properly between concrete shadow classes for resetters...
    230     if (!useLegacy() && RuntimeEnvironment.getApiLevel() >= P) {
    231       ReflectionHelpers.setStaticField(AssetManager.class, "sSystemApkAssetsSet", null);
    232       ReflectionHelpers.setStaticField(AssetManager.class, "sSystemApkAssets", null);
    233       ReflectionHelpers.setStaticField(AssetManager.class, "sSystem", null);
    234     }
    235   }
    236 
    237   // Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
    238   static int ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
    239     return cookie.intValue() != kInvalidCookie ? (cookie.intValue() + 1) : -1;
    240   }
    241 
    242   static ApkAssetsCookie JavaCookieToApkAssetsCookie(int cookie) {
    243     return ApkAssetsCookie.forInt(cookie > 0 ? (cookie - 1) : kInvalidCookie);
    244   }
    245 
    246   // This is called by zygote (running as user root) as part of preloadResources.
    247 // static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
    248   @Implementation(minSdk = P)
    249   protected static void nativeVerifySystemIdmaps() {
    250     return;
    251 
    252     // todo: maybe implement?
    253     // switch (pid_t pid = fork()) {
    254     //   case -1:
    255     //     PLOG(ERROR) << "failed to fork for idmap";
    256     //     break;
    257     //
    258     //   // child
    259     //   case 0: {
    260     //     struct __user_cap_header_struct capheader;
    261     //     struct __user_cap_data_struct capdata;
    262     //
    263     //     memset(&capheader, 0, sizeof(capheader));
    264     //     memset(&capdata, 0, sizeof(capdata));
    265     //
    266     //     capheader.version = _LINUX_CAPABILITY_VERSION;
    267     //     capheader.pid = 0;
    268     //
    269     //     if (capget(&capheader, &capdata) != 0) {
    270     //       PLOG(ERROR) << "capget";
    271     //       exit(1);
    272     //     }
    273     //
    274     //     capdata.effective = capdata.permitted;
    275     //     if (capset(&capheader, &capdata) != 0) {
    276     //       PLOG(ERROR) << "capset";
    277     //       exit(1);
    278     //     }
    279     //
    280     //     if (setgid(AID_SYSTEM) != 0) {
    281     //       PLOG(ERROR) << "setgid";
    282     //       exit(1);
    283     //     }
    284     //
    285     //     if (setuid(AID_SYSTEM) != 0) {
    286     //       PLOG(ERROR) << "setuid";
    287     //       exit(1);
    288     //     }
    289     //
    290     //     // Generic idmap parameters
    291     //     char* argv[8];
    292     //     int argc = 0;
    293     //     struct stat st;
    294     //
    295     //     memset(argv, 0, sizeof(argv));
    296     //     argv[argc++] = AssetManager.IDMAP_BIN;
    297     //     argv[argc++] = "--scan";
    298     //     argv[argc++] = AssetManager.TARGET_PACKAGE_NAME;
    299     //     argv[argc++] = AssetManager.TARGET_APK_PATH;
    300     //     argv[argc++] = AssetManager.IDMAP_DIR;
    301     //
    302     //     // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
    303     //     // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
    304     //     String overlay_theme_path = base.GetProperty(AssetManager.OVERLAY_THEME_DIR_PROPERTY,
    305     //         "");
    306     //     if (!overlay_theme_path.empty()) {
    307     //       overlay_theme_path = String(AssetManager.OVERLAY_DIR) + "/" + overlay_theme_path;
    308     //       if (stat(overlay_theme_path, &st) == 0) {
    309     //         argv[argc++] = overlay_theme_path;
    310     //       }
    311     //     }
    312     //
    313     //     if (stat(AssetManager.OVERLAY_DIR, &st) == 0) {
    314     //       argv[argc++] = AssetManager.OVERLAY_DIR;
    315     //     }
    316     //
    317     //     if (stat(AssetManager.PRODUCT_OVERLAY_DIR, &st) == 0) {
    318     //       argv[argc++] = AssetManager.PRODUCT_OVERLAY_DIR;
    319     //     }
    320     //
    321     //     // Finally, invoke idmap (if any overlay directory exists)
    322     //     if (argc > 5) {
    323     //       execv(AssetManager.IDMAP_BIN, (char* const*)argv);
    324     //       PLOG(ERROR) << "failed to execv for idmap";
    325     //       exit(1); // should never get here
    326     //     } else {
    327     //       exit(0);
    328     //     }
    329     //   } break;
    330     //
    331     //   // parent
    332     //   default:
    333     //     waitpid(pid, null, 0);
    334     //     break;
    335     // }
    336   }
    337 
    338   // BEGIN-INTERNAL
    339   @Implementation(minSdk = Build.VERSION_CODES.Q)
    340   protected static String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid() {
    341     return new String[0];
    342   }
    343   // END-INTERNAL
    344 
    345   static int CopyValue(/*JNIEnv* env,*/ ApkAssetsCookie cookie, Res_value value, int ref,
    346       int type_spec_flags, ResTable_config config, TypedValue out_typed_value) {
    347     out_typed_value.type = value.dataType;
    348     out_typed_value.assetCookie = ApkAssetsCookieToJavaCookie(cookie);
    349     out_typed_value.data = value.data;
    350     out_typed_value.string = null;
    351     out_typed_value.resourceId = ref;
    352     out_typed_value.changingConfigurations = type_spec_flags;
    353     if (config != null) {
    354       out_typed_value.density = config.density;
    355     }
    356     return (int) (ApkAssetsCookieToJavaCookie(cookie));
    357   }
    358 
    359 //  @Override
    360 //  protected int addAssetPathNative(String path) {
    361 //    throw new UnsupportedOperationException(); // todo
    362 //  }
    363 
    364   @Override
    365   Collection<FsFile> getAllAssetDirs() {
    366     ApkAssets[] apkAssetsArray = ReflectionHelpers.callInstanceMethod(realAssetManager, "getApkAssets");
    367     ArrayList<FsFile> fsFiles = new ArrayList<>();
    368     for (ApkAssets apkAssets : apkAssetsArray) {
    369       long apk_assets_native_ptr = ((ShadowArscApkAssets9) Shadow.extract(apkAssets)).getNativePtr();
    370       CppApkAssets cppApkAssets = Registries.NATIVE_APK_ASSETS_REGISTRY.getNativeObject(apk_assets_native_ptr);
    371 
    372       if (new File(cppApkAssets.GetPath()).isFile()) {
    373         fsFiles.add(Fs.newJarFile(new File(cppApkAssets.GetPath())).join("assets"));
    374       } else {
    375         fsFiles.add(Fs.newFile(cppApkAssets.GetPath()));
    376       }
    377     }
    378     return fsFiles;
    379   }
    380 
    381   @Override
    382   List<AssetPath> getAssetPaths() {
    383     return AssetManagerForJavaObject(realAssetManager).getAssetPaths();
    384   }
    385 
    386 // ----------------------------------------------------------------------------
    387 
    388   // interface AAssetManager {}
    389   //
    390   // // Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
    391   // static class GuardedAssetManager implements AAssetManager {
    392   //   CppAssetManager2 guarded_assetmanager = new CppAssetManager2();
    393   // }
    394 
    395   static CppAssetManager2 NdkAssetManagerForJavaObject(/* JNIEnv* env,*/ AssetManager jassetmanager) {
    396     // long assetmanager_handle = env.GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
    397     long assetmanager_handle = ReflectionHelpers.getField(jassetmanager, "mObject");
    398     CppAssetManager2 am = Registries.NATIVE_ASSET_MANAGER_REGISTRY.getNativeObject(assetmanager_handle);
    399     if (am == null) {
    400       throw new IllegalStateException("AssetManager has been finalized!");
    401     }
    402     return am;
    403   }
    404 
    405   static CppAssetManager2 AssetManagerForJavaObject(/* JNIEnv* env,*/ AssetManager jassetmanager) {
    406     return NdkAssetManagerForJavaObject(jassetmanager);
    407   }
    408 
    409   static CppAssetManager2 AssetManagerFromLong(long ptr) {
    410     // return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager>(ptr));
    411     return Registries.NATIVE_ASSET_MANAGER_REGISTRY.getNativeObject(ptr);
    412   }
    413 
    414   static ParcelFileDescriptor ReturnParcelFileDescriptor(/* JNIEnv* env,*/ Asset asset,
    415       long[] out_offsets) throws FileNotFoundException {
    416     final Ref<Long> start_offset = new Ref<>(0L);
    417     final Ref<Long> length = new Ref<>(0L);
    418     FileDescriptor fd = asset.openFileDescriptor(start_offset, length);
    419     // asset.reset();
    420 
    421     if (fd == null) {
    422       throw new FileNotFoundException(
    423           "This file can not be opened as a file descriptor; it is probably compressed");
    424     }
    425 
    426     long[] offsets = out_offsets; // reinterpret_cast<long*>(env.GetPrimitiveArrayCritical(out_offsets, 0));
    427     if (offsets == null) {
    428       // close(fd);
    429       return null;
    430     }
    431 
    432     offsets[0] = start_offset.get();
    433     offsets[1] = length.get();
    434 
    435     // env.ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
    436 
    437     FileDescriptor file_desc = fd; // jniCreateFileDescriptor(env, fd);
    438     // if (file_desc == null) {
    439     //   close(fd);
    440     //   return null;
    441     // }
    442 
    443     // TODO: consider doing this
    444     // return new ParcelFileDescriptor(file_desc);
    445     return ParcelFileDescriptor.open(asset.getFile(), ParcelFileDescriptor.MODE_READ_ONLY);
    446   }
    447 
    448   /**
    449    * Used for the creation of system assets.
    450    */
    451   @Implementation(minSdk = P)
    452   protected void __constructor__(boolean sentinel) {
    453     inNonSystemConstructor = true;
    454     try {
    455       // call real constructor so field initialization happens.
    456       invokeConstructor(
    457           AssetManager.class, realAssetManager, ClassParameter.from(boolean.class, sentinel));
    458     } finally {
    459       inNonSystemConstructor = false;
    460     }
    461   }
    462 
    463   // static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
    464   @Implementation(minSdk = P)
    465   protected static int getGlobalAssetCount() {
    466     return Asset.getGlobalCount();
    467   }
    468 
    469   // static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
    470   @Implementation(minSdk = P)
    471   protected static String getAssetAllocations() {
    472     String alloc = Asset.getAssetAllocations();
    473     if (alloc.length() <= 0) {
    474       return null;
    475     }
    476     return alloc;
    477   }
    478 
    479   // static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
    480   @Implementation(minSdk = P)
    481   protected static int getGlobalAssetManagerCount() {
    482     // TODO(adamlesinski): Switch to AssetManager2.
    483     return CppAssetManager.getGlobalCount();
    484   }
    485 
    486   // static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
    487   @Implementation(minSdk = P)
    488   protected static long nativeCreate() {
    489     // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
    490     // AssetManager2 in a contiguous block (GuardedAssetManager).
    491     // return reinterpret_cast<long>(new GuardedAssetManager());
    492 
    493     long cppAssetManagerRef;
    494 
    495     // we want to share a single instance of the system CppAssetManager2
    496     if (inNonSystemConstructor) {
    497       CppAssetManager2 appAssetManager = new CppAssetManager2();
    498       cppAssetManagerRef = Registries.NATIVE_ASSET_MANAGER_REGISTRY.register(appAssetManager);
    499     } else {
    500       if (systemCppAssetManager2 == null) {
    501         systemCppAssetManager2 = new CppAssetManager2();
    502         systemCppAssetManager2Ref =
    503             Registries.NATIVE_ASSET_MANAGER_REGISTRY.register(systemCppAssetManager2);
    504       }
    505 
    506       cppAssetManagerRef = systemCppAssetManager2Ref;
    507     }
    508 
    509     return cppAssetManagerRef;
    510   }
    511 
    512     // static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
    513   @Implementation(minSdk = P)
    514   protected static void nativeDestroy(long ptr) {
    515     if (ptr == systemCppAssetManager2Ref) {
    516       // don't destroy the shared system CppAssetManager2!
    517       return;
    518     }
    519 
    520     // delete reinterpret_cast<GuardedAssetManager*>(ptr);
    521     Registries.NATIVE_ASSET_MANAGER_REGISTRY.unregister(ptr);
    522   }
    523 
    524   // static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    525 //                                jobjectArray apk_assets_array, jboolean invalidate_caches) {
    526   @Implementation(minSdk = P)
    527   protected static void nativeSetApkAssets(long ptr, @NonNull android.content.res.ApkAssets[] apk_assets_array,
    528       boolean invalidate_caches) {
    529     ATRACE_NAME("AssetManager::SetApkAssets");
    530 
    531     int apk_assets_len = apk_assets_array.length;
    532     List<CppApkAssets> apk_assets = new ArrayList<>();
    533     // apk_assets.reserve(apk_assets_len);
    534     for (int i = 0; i < apk_assets_len; i++) {
    535       android.content.res.ApkAssets apkAssets = apk_assets_array[i]; // env.GetObjectArrayElement(apk_assets_array, i);
    536       if (apkAssets == null) {
    537         throw new NullPointerException(String.format("ApkAssets at index %d is null", i));
    538       }
    539 
    540       long apk_assets_native_ptr = ((ShadowArscApkAssets9) Shadow.extract(apkAssets)).getNativePtr();
    541       // if (env.ExceptionCheck()) {
    542       //   return;
    543       // }
    544       apk_assets.add(Registries.NATIVE_APK_ASSETS_REGISTRY.getNativeObject(apk_assets_native_ptr));
    545     }
    546 
    547     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    548     assetmanager.SetApkAssets(apk_assets, invalidate_caches);
    549   }
    550 
    551   // static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
    552 //                                    jstring locale, jint orientation, jint touchscreen, jint density,
    553 //                                    jint keyboard, jint keyboard_hidden, jint navigation,
    554 //                                    jint screen_width, jint screen_height,
    555 //                                    jint smallest_screen_width_dp, jint screen_width_dp,
    556 //                                    jint screen_height_dp, jint screen_layout, jint ui_mode,
    557 //                                    jint color_mode, jint major_version) {
    558   @Implementation(minSdk = P)
    559   protected static void nativeSetConfiguration(long ptr, int mcc, int mnc,
    560       @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
    561       int keyboard_hidden, int navigation, int screen_width, int screen_height,
    562       int smallest_screen_width_dp, int screen_width_dp, int screen_height_dp, int screen_layout,
    563       int ui_mode, int color_mode, int major_version) {
    564     ATRACE_NAME("AssetManager::SetConfiguration");
    565 
    566     ResTable_config configuration = new ResTable_config();
    567     // memset(&configuration, 0, sizeof(configuration));
    568     configuration.mcc = (short) (mcc);
    569     configuration.mnc = (short) (mnc);
    570     configuration.orientation = (byte) (orientation);
    571     configuration.touchscreen = (byte) (touchscreen);
    572     configuration.density = (short) (density);
    573     configuration.keyboard = (byte) (keyboard);
    574     configuration.inputFlags = (byte) (keyboard_hidden);
    575     configuration.navigation = (byte) (navigation);
    576     configuration.screenWidth = (short) (screen_width);
    577     configuration.screenHeight = (short) (screen_height);
    578     configuration.smallestScreenWidthDp = (short) (smallest_screen_width_dp);
    579     configuration.screenWidthDp = (short) (screen_width_dp);
    580     configuration.screenHeightDp = (short) (screen_height_dp);
    581     configuration.screenLayout = (byte) (screen_layout);
    582     configuration.uiMode = (byte) (ui_mode);
    583     configuration.colorMode = (byte) (color_mode);
    584     configuration.sdkVersion = (short) (major_version);
    585 
    586     if (locale != null) {
    587       String locale_utf8 = locale;
    588       CHECK(locale_utf8 != null);
    589       configuration.setBcp47Locale(locale_utf8);
    590     }
    591 
    592     // Constants duplicated from Java class android.content.res.Configuration.
    593     int kScreenLayoutRoundMask = 0x300;
    594     int kScreenLayoutRoundShift = 8;
    595 
    596     // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
    597     // in C++. We must extract the round qualifier out of the Java screenLayout and put it
    598     // into screenLayout2.
    599     configuration.screenLayout2 =
    600         (byte) ((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
    601 
    602     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    603     assetmanager.SetConfiguration(configuration);
    604   }
    605 
    606   // static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
    607   @Implementation(minSdk = P)
    608   protected static @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
    609       long ptr) {
    610     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    611 
    612     SparseArray<String> sparse_array =
    613         new SparseArray<>();
    614 
    615     if (sparse_array == null) {
    616       // An exception is pending.
    617       return null;
    618     }
    619 
    620     assetmanager.ForEachPackage((String package_name, byte package_id) -> {
    621       String jpackage_name = package_name; // env.NewStringUTF(package_name);
    622       if (jpackage_name == null) {
    623         // An exception is pending.
    624         return;
    625       }
    626 
    627       // env.CallVoidMethod(sparse_array, gSparseArrayOffsets.put, (int) (package_id),
    628       //     jpackage_name);
    629       sparse_array.put(package_id, jpackage_name);
    630     });
    631     return sparse_array;
    632   }
    633 
    634   // static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
    635   @Implementation(minSdk = P)
    636   protected static @Nullable String[] nativeList(long ptr, @NonNull String path)
    637       throws IOException {
    638     String path_utf8 = path;
    639     if (path_utf8 == null) {
    640       // This will throw NPE.
    641       return null;
    642     }
    643 
    644     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    645     AssetDir asset_dir =
    646         assetmanager.OpenDir(path_utf8);
    647     if (asset_dir == null) {
    648       throw new FileNotFoundException(path_utf8);
    649     }
    650 
    651     int file_count = asset_dir.getFileCount();
    652 
    653     String[] array = new String[file_count]; // env.NewObjectArray(file_count, g_stringClass, null);
    654     // if (array == null) {
    655     //   return null;
    656     // }
    657 
    658     for (int i = 0; i < file_count; i++) {
    659       String java_string = asset_dir.getFileName(i).string();
    660 
    661       // Check for errors creating the strings (if malformed or no memory).
    662       // if (env.ExceptionCheck()) {
    663       //   return null;
    664       // }
    665 
    666       // env.SetObjectArrayElement(array, i, java_string);
    667       array[i] = java_string;
    668 
    669       // If we have a large amount of string in our array, we might overflow the
    670       // local reference table of the VM.
    671       // env.DeleteLocalRef(java_string);
    672     }
    673     return array;
    674   }
    675 
    676   // static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
    677 //                              jint access_mode) {
    678   @Implementation(minSdk = P)
    679   protected static long nativeOpenAsset(long ptr, @NonNull String asset_path, int access_mode)
    680       throws FileNotFoundException {
    681     String asset_path_utf8 = asset_path;
    682     if (asset_path_utf8 == null) {
    683       // This will throw NPE.
    684       return 0;
    685     }
    686 
    687     ATRACE_NAME(String.format("AssetManager::OpenAsset(%s)", asset_path_utf8));
    688 
    689     if (access_mode != Asset.AccessMode.ACCESS_UNKNOWN.mode()
    690         && access_mode != Asset.AccessMode.ACCESS_RANDOM.mode()
    691         && access_mode != Asset.AccessMode.ACCESS_STREAMING.mode()
    692         && access_mode != Asset.AccessMode.ACCESS_BUFFER.mode()) {
    693       throw new IllegalArgumentException("Bad access mode");
    694     }
    695 
    696     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    697     Asset asset =
    698         assetmanager.Open(asset_path_utf8, Asset.AccessMode.fromInt(access_mode));
    699     if (!isTruthy(asset)) {
    700       throw new FileNotFoundException(asset_path_utf8);
    701     }
    702     return Registries.NATIVE_ASSET_REGISTRY.register(asset);
    703   }
    704 
    705   // static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
    706 //                                  jlongArray out_offsets) {
    707   @Implementation(minSdk = P)
    708   protected static ParcelFileDescriptor nativeOpenAssetFd(long ptr,
    709       @NonNull String asset_path, long[] out_offsets) throws IOException {
    710     String asset_path_utf8 = asset_path;
    711     if (asset_path_utf8 == null) {
    712       // This will throw NPE.
    713       return null;
    714     }
    715 
    716     ATRACE_NAME(String.format("AssetManager::OpenAssetFd(%s)", asset_path_utf8));
    717 
    718     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    719     Asset asset = assetmanager.Open(asset_path_utf8, Asset.AccessMode.ACCESS_RANDOM);
    720     if (!isTruthy(asset)) {
    721       throw new FileNotFoundException(asset_path_utf8);
    722     }
    723     return ReturnParcelFileDescriptor(asset, out_offsets);
    724   }
    725 
    726   // static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
    727 //                                 jstring asset_path, jint access_mode) {
    728   @Implementation(minSdk = P)
    729   protected static long nativeOpenNonAsset(long ptr, int jcookie, @NonNull String asset_path,
    730       int access_mode) throws FileNotFoundException {
    731     ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    732     String asset_path_utf8 = asset_path;
    733     if (asset_path_utf8 == null) {
    734       // This will throw NPE.
    735       return 0;
    736     }
    737 
    738     ATRACE_NAME(String.format("AssetManager::OpenNonAsset(%s)", asset_path_utf8));
    739 
    740     if (access_mode != Asset.AccessMode.ACCESS_UNKNOWN.mode()
    741         && access_mode != Asset.AccessMode.ACCESS_RANDOM.mode()
    742         && access_mode != Asset.AccessMode.ACCESS_STREAMING.mode()
    743         && access_mode != Asset.AccessMode.ACCESS_BUFFER.mode()) {
    744       throw new IllegalArgumentException("Bad access mode");
    745     }
    746 
    747     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    748     Asset asset;
    749     if (cookie.intValue() != kInvalidCookie) {
    750       asset = assetmanager.OpenNonAsset(asset_path_utf8, cookie,
    751           Asset.AccessMode.fromInt(access_mode));
    752     } else {
    753       asset = assetmanager.OpenNonAsset(asset_path_utf8,
    754           Asset.AccessMode.fromInt(access_mode));
    755     }
    756 
    757     if (!isTruthy(asset)) {
    758       throw new FileNotFoundException(asset_path_utf8);
    759     }
    760     return Registries.NATIVE_ASSET_REGISTRY.register(asset);
    761   }
    762 
    763   // static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
    764 //                                     jstring asset_path, jlongArray out_offsets) {
    765   @Implementation(minSdk = P)
    766   protected static @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int jcookie,
    767       @NonNull String asset_path, @NonNull long[] out_offsets) throws IOException {
    768     ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    769     String asset_path_utf8 = asset_path;
    770     if (asset_path_utf8 == null) {
    771       // This will throw NPE.
    772       return null;
    773     }
    774 
    775     ATRACE_NAME(String.format("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8));
    776 
    777     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    778     Asset asset;
    779     if (cookie.intValue() != kInvalidCookie) {
    780       asset = assetmanager.OpenNonAsset(asset_path_utf8, cookie, Asset.AccessMode.ACCESS_RANDOM);
    781     } else {
    782       asset = assetmanager.OpenNonAsset(asset_path_utf8, Asset.AccessMode.ACCESS_RANDOM);
    783     }
    784 
    785     if (!isTruthy(asset)) {
    786       throw new FileNotFoundException(asset_path_utf8);
    787     }
    788     return ReturnParcelFileDescriptor(asset, out_offsets);
    789   }
    790 
    791   // static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
    792 //                                 jstring asset_path) {
    793   @Implementation(minSdk = P)
    794   protected static long nativeOpenXmlAsset(long ptr, int jcookie, @NonNull String asset_path)
    795       throws FileNotFoundException {
    796     ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
    797     String asset_path_utf8 = asset_path;
    798     if (asset_path_utf8 == null) {
    799       // This will throw NPE.
    800       return 0;
    801     }
    802 
    803     ATRACE_NAME(String.format("AssetManager::OpenXmlAsset(%s)", asset_path_utf8));
    804 
    805     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    806     Asset asset;
    807     if (cookie.intValue() != kInvalidCookie) {
    808       asset = assetmanager.OpenNonAsset(asset_path_utf8, cookie, Asset.AccessMode.ACCESS_RANDOM);
    809     } else {
    810       Ref<ApkAssetsCookie> cookieRef = new Ref<>(cookie);
    811       asset = assetmanager.OpenNonAsset(asset_path_utf8, Asset.AccessMode.ACCESS_RANDOM, cookieRef);
    812       cookie = cookieRef.get();
    813     }
    814 
    815     if (!isTruthy(asset)) {
    816       throw new FileNotFoundException(asset_path_utf8);
    817     }
    818 
    819     // May be nullptr.
    820     DynamicRefTable dynamic_ref_table = assetmanager.GetDynamicRefTableForCookie(cookie);
    821 
    822     ResXMLTree xml_tree = new ResXMLTree(dynamic_ref_table);
    823     int err = xml_tree.setTo(asset.getBuffer(true), (int) asset.getLength(), true);
    824     // asset.reset();
    825 
    826     if (err != NO_ERROR) {
    827       throw new FileNotFoundException("Corrupt XML binary file");
    828     }
    829     return NATIVE_RES_XML_TREES.register(xml_tree);
    830   }
    831 
    832   // static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
    833 //                                    jshort density, jobject typed_value,
    834 //                                    jboolean resolve_references) {
    835   @Implementation(minSdk = P)
    836   protected static int nativeGetResourceValue(long ptr, @AnyRes int resid, short density,
    837       @NonNull TypedValue typed_value, boolean resolve_references) {
    838     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    839     final Ref<Res_value> value = new Ref<>(null);
    840     final Ref<ResTable_config> selected_config = new Ref<>(null);
    841     final Ref<Integer> flags = new Ref<>(0);
    842     ApkAssetsCookie cookie =
    843         assetmanager.GetResource(resid, false /*may_be_bag*/,
    844             (short) (density), value, selected_config, flags);
    845     if (cookie.intValue() == kInvalidCookie) {
    846       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
    847     }
    848 
    849     final Ref<Integer> ref = new Ref<>(resid);
    850     if (resolve_references) {
    851       cookie = assetmanager.ResolveReference(cookie, value, selected_config, flags, ref);
    852       if (cookie.intValue() == kInvalidCookie) {
    853         return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
    854       }
    855     }
    856     return CopyValue(cookie, value.get(), ref.get(), flags.get(), selected_config.get(), typed_value);
    857   }
    858 
    859   // static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
    860 //                                       jint bag_entry_id, jobject typed_value) {
    861   @Implementation(minSdk = P)
    862   protected static int nativeGetResourceBagValue(long ptr, @AnyRes int resid, int bag_entry_id,
    863       @NonNull TypedValue typed_value) {
    864     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    865     ResolvedBag bag = assetmanager.GetBag(resid);
    866     if (bag == null) {
    867       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
    868     }
    869 
    870     final Ref<Integer> type_spec_flags = new Ref<>(bag.type_spec_flags);
    871     ApkAssetsCookie cookie = K_INVALID_COOKIE;
    872     Res_value bag_value = null;
    873     for (ResolvedBag.Entry entry : bag.entries) {
    874       if (entry.key == (int) (bag_entry_id)) {
    875         cookie = entry.cookie;
    876         bag_value = entry.value;
    877 
    878         // Keep searching (the old implementation did that).
    879       }
    880     }
    881 
    882     if (cookie.intValue() == kInvalidCookie) {
    883       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
    884     }
    885 
    886     final Ref<Res_value> value = new Ref<>(bag_value);
    887     final Ref<Integer> ref = new Ref<>(resid);
    888     final Ref<ResTable_config> selected_config = new Ref<>(null);
    889     cookie = assetmanager.ResolveReference(cookie, value, selected_config, type_spec_flags, ref);
    890     if (cookie.intValue() == kInvalidCookie) {
    891       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
    892     }
    893     return CopyValue(cookie, value.get(), ref.get(), type_spec_flags.get(), null, typed_value);
    894   }
    895 
    896   // static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
    897   @Implementation(minSdk = P)
    898   protected static @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
    899       @StyleRes int resid) {
    900     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    901     ResolvedBag bag = assetmanager.GetBag(resid);
    902     if (bag == null) {
    903       return null;
    904     }
    905 
    906     int[] array = new int[bag.entry_count];
    907     // if (env.ExceptionCheck()) {
    908     //   return null;
    909     // }
    910 
    911     for (int i = 0; i < bag.entry_count; i++) {
    912       int attr_resid = bag.entries[i].key;
    913       // env.SetIntArrayRegion(array, i, 1, &attr_resid);
    914       array[i] = attr_resid;
    915     }
    916     return array;
    917   }
    918 
    919   // static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    920 //                                                  jint resid) {
    921   @Implementation(minSdk = P)
    922   protected static @Nullable String[] nativeGetResourceStringArray(long ptr,
    923       @ArrayRes int resid) {
    924     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    925     ResolvedBag bag = assetmanager.GetBag(resid);
    926     if (bag == null) {
    927       return null;
    928     }
    929 
    930     String[] array = new String[bag.entry_count];
    931     if (array == null) {
    932       return null;
    933     }
    934 
    935     for (int i = 0; i < bag.entry_count; i++) {
    936       ResolvedBag.Entry entry = bag.entries[i];
    937 
    938       // Resolve any references to their final value.
    939       final Ref<Res_value> value = new Ref<>(entry.value);
    940       final Ref<ResTable_config> selected_config = new Ref<>(null);
    941       final Ref<Integer> flags = new Ref<>(0);
    942       final Ref<Integer> ref = new Ref<>(0);
    943       ApkAssetsCookie cookie =
    944           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
    945       if (cookie.intValue() == kInvalidCookie) {
    946         return null;
    947       }
    948 
    949       if (value.get().dataType == Res_value.TYPE_STRING) {
    950         CppApkAssets apk_assets = assetmanager.GetApkAssets().get(cookie.intValue());
    951         ResStringPool pool = apk_assets.GetLoadedArsc().GetStringPool();
    952 
    953         String java_string = null;
    954         int str_len;
    955         String str_utf8 = pool.stringAt(value.get().data);
    956         if (str_utf8 != null) {
    957           java_string = str_utf8;
    958         } else {
    959           String str_utf16 = pool.stringAt(value.get().data);
    960           java_string = str_utf16;
    961         }
    962 
    963         // // Check for errors creating the strings (if malformed or no memory).
    964         // if (env.ExceptionCheck()) {
    965         //   return null;
    966         // }
    967 
    968         // env.SetObjectArrayElement(array, i, java_string);
    969         array[i] = java_string;
    970 
    971         // If we have a large amount of string in our array, we might overflow the
    972         // local reference table of the VM.
    973         // env.DeleteLocalRef(java_string);
    974       }
    975     }
    976     return array;
    977   }
    978 
    979   // static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
    980 //                                                   jint resid) {
    981   @Implementation(minSdk = P)
    982   protected static @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
    983       @ArrayRes int resid) {
    984     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
    985     ResolvedBag bag = assetmanager.GetBag(resid);
    986     if (bag == null) {
    987       return null;
    988     }
    989 
    990     int[] array = new int[bag.entry_count * 2];
    991     // if (array == null) {
    992     //   return null;
    993     // }
    994 
    995     int[] buffer = array; //reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null));
    996     // if (buffer == null) {
    997     //   return null;
    998     // }
    999 
   1000     for (int i = 0; i < bag.entry_count; i++) {
   1001       ResolvedBag.Entry entry = bag.entries[i];
   1002       final Ref<Res_value> value = new Ref<>(entry.value);
   1003       final Ref<ResTable_config> selected_config = new Ref<>(null);
   1004       final Ref<Integer> flags = new Ref<>(0);
   1005       final Ref<Integer> ref = new Ref<>(0);
   1006       ApkAssetsCookie cookie =
   1007           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
   1008       if (cookie.intValue() == kInvalidCookie) {
   1009         // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
   1010         return null;
   1011       }
   1012 
   1013       int string_index = -1;
   1014       if (value.get().dataType == Res_value.TYPE_STRING) {
   1015         string_index = (int) (value.get().data);
   1016       }
   1017 
   1018       buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
   1019       buffer[(i * 2) + 1] = string_index;
   1020     }
   1021     // env.ReleasePrimitiveArrayCritical(array, buffer, 0);
   1022     return array;
   1023   }
   1024 
   1025   // static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
   1026   @Implementation(minSdk = P)
   1027   protected static @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resid) {
   1028     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1029     ResolvedBag bag = assetmanager.GetBag(resid);
   1030     if (bag == null) {
   1031       return null;
   1032     }
   1033 
   1034     int[] array = new int[bag.entry_count];
   1035     // if (array == null) {
   1036     //   return null;
   1037     // }
   1038 
   1039     int[] buffer = array; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null));
   1040     // if (buffer == null) {
   1041     //   return null;
   1042     // }
   1043 
   1044     for (int i = 0; i < bag.entry_count; i++) {
   1045       ResolvedBag.Entry entry = bag.entries[i];
   1046       final Ref<Res_value> value = new Ref<>(entry.value);
   1047       final Ref<ResTable_config> selected_config = new Ref<>(null);
   1048       final Ref<Integer> flags = new Ref<>(0);
   1049       final Ref<Integer> ref = new Ref<>(0);
   1050       ApkAssetsCookie cookie =
   1051           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
   1052       if (cookie.intValue() == kInvalidCookie) {
   1053         // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
   1054         return null;
   1055       }
   1056 
   1057       if (value.get().dataType >= Res_value.TYPE_FIRST_INT && value.get().dataType <= Res_value.TYPE_LAST_INT) {
   1058         buffer[i] = (int) (value.get().data);
   1059       }
   1060     }
   1061     // env.ReleasePrimitiveArrayCritical(array, buffer, 0);
   1062     return array;
   1063   }
   1064 
   1065   // static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
   1066   @Implementation(minSdk = P)
   1067   protected static int nativeGetResourceArraySize(long ptr, @ArrayRes int resid) {
   1068     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1069     ResolvedBag bag = assetmanager.GetBag(resid);
   1070     if (bag == null) {
   1071       return -1;
   1072     }
   1073     return (int) (bag.entry_count);
   1074   }
   1075 
   1076   // static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
   1077 //                                    jintArray out_data) {
   1078   @Implementation(minSdk = P)
   1079   protected static int nativeGetResourceArray(long ptr, @ArrayRes int resid,
   1080       @NonNull int[] out_data) {
   1081     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1082     ResolvedBag bag = assetmanager.GetBag(resid);
   1083     if (bag == null) {
   1084       return -1;
   1085     }
   1086 
   1087     int out_data_length = out_data.length;
   1088     // if (env.ExceptionCheck()) {
   1089     //   return -1;
   1090     // }
   1091 
   1092     if ((int) (bag.entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
   1093       throw new IllegalArgumentException("Input array is not large enough");
   1094     }
   1095 
   1096     int[] buffer = out_data; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_data, null));
   1097     if (buffer == null) {
   1098       return -1;
   1099     }
   1100 
   1101     int[] cursor = buffer;
   1102     for (int i = 0; i < bag.entry_count; i++) {
   1103       ResolvedBag.Entry entry = bag.entries[i];
   1104       final Ref<Res_value> value = new Ref<>(entry.value);
   1105       final Ref<ResTable_config> selected_config = new Ref<>(new ResTable_config());
   1106       selected_config.get().density = 0;
   1107       final Ref<Integer> flags = new Ref<>(bag.type_spec_flags);
   1108       final Ref<Integer> ref = new Ref<>(0);
   1109       ApkAssetsCookie cookie =
   1110           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
   1111       if (cookie.intValue() == kInvalidCookie) {
   1112         // env.ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
   1113         return -1;
   1114       }
   1115 
   1116       // Deal with the special @null value -- it turns back to TYPE_NULL.
   1117       if (value.get().dataType == Res_value.TYPE_REFERENCE && value.get().data == 0) {
   1118         value.set(Res_value.NULL_VALUE);
   1119       }
   1120 
   1121       int offset = i * STYLE_NUM_ENTRIES;
   1122       cursor[offset + STYLE_TYPE] = (int) (value.get().dataType);
   1123       cursor[offset + STYLE_DATA] = (int) (value.get().data);
   1124       cursor[offset + STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
   1125       cursor[offset + STYLE_RESOURCE_ID] = (int) (ref.get());
   1126       cursor[offset + STYLE_CHANGING_CONFIGURATIONS] = (int) (flags.get());
   1127       cursor[offset + STYLE_DENSITY] = (int) (selected_config.get().density);
   1128       // cursor += STYLE_NUM_ENTRIES;
   1129     }
   1130     // env.ReleasePrimitiveArrayCritical(out_data, buffer, 0);
   1131     return (int) (bag.entry_count);
   1132   }
   1133 
   1134   // static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
   1135 //                                         jstring def_type, jstring def_package) {
   1136   @Implementation(minSdk = P)
   1137   protected static @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
   1138       @Nullable String def_type, @Nullable String def_package) {
   1139     String name_utf8 = name;
   1140     if (name_utf8 == null) {
   1141       // This will throw NPE.
   1142       return 0;
   1143     }
   1144 
   1145     String type = null;
   1146     if (def_type != null) {
   1147       String type_utf8 = def_type;
   1148       CHECK(type_utf8 != null);
   1149       type = type_utf8;
   1150     }
   1151 
   1152     String package_ = null;
   1153     if (def_package != null) {
   1154       String package_utf8 = def_package;
   1155       CHECK(package_utf8 != null);
   1156       package_ = package_utf8;
   1157     }
   1158     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1159     return (int) (assetmanager.GetResourceId(name_utf8, type, package_));
   1160   }
   1161 
   1162   // static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
   1163   @Implementation(minSdk = P)
   1164   protected static @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid) {
   1165     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1166     CppAssetManager2.ResourceName name = new ResourceName();
   1167     if (!assetmanager.GetResourceName(resid, name)) {
   1168       return null;
   1169     }
   1170 
   1171     StringBuilder result = new StringBuilder();
   1172     if (name.package_ != null) {
   1173       result.append(name.package_/*, name.package_len*/);
   1174     }
   1175 
   1176     if (name.type != null /*|| name.type16 != null*/) {
   1177       if (!(result.length() == 0)) {
   1178         result.append(":");
   1179       }
   1180 
   1181       // if (name.type != null) {
   1182         result.append(name.type/*, name.type_len*/);
   1183       // } else {
   1184       //   result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.type16 /*, name.type_len))*/);
   1185       // }
   1186     }
   1187 
   1188     if (name.entry != null /*|| name.entry16 != null*/) {
   1189       if (!(result.length() == 0)) {
   1190         result.append("/");
   1191       }
   1192 
   1193       // if (name.entry != null) {
   1194         result.append(name.entry/*, name.entry_len*/);
   1195       // } else {
   1196       //   result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.entry16 /*, name.entry_len)*/);
   1197       // }
   1198     }
   1199     return result.toString();
   1200   }
   1201 
   1202   // static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
   1203   @Implementation(minSdk = P)
   1204   protected static @Nullable String nativeGetResourcePackageName(long ptr,
   1205       @AnyRes int resid) {
   1206     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1207     final ResourceName name = new ResourceName();
   1208     if (!assetmanager.GetResourceName(resid, name)) {
   1209       return null;
   1210     }
   1211 
   1212     if (name.package_ != null) {
   1213       return name.package_;
   1214     }
   1215     return null;
   1216   }
   1217 
   1218   // static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
   1219   @Implementation(minSdk = P)
   1220   protected static @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid) {
   1221     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1222     final ResourceName name = new ResourceName();
   1223     if (!assetmanager.GetResourceName(resid, name)) {
   1224       return null;
   1225     }
   1226 
   1227     if (name.type != null) {
   1228       return name.type;
   1229     // } else if (name.get().type16 != null) {
   1230     //   return name.get().type16; // env.NewString(reinterpret_cast<jchar*>(name.type16), name.type_len);
   1231     }
   1232     return null;
   1233   }
   1234 
   1235   // static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
   1236   @Implementation(minSdk = P)
   1237   protected static @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid) {
   1238     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1239     final ResourceName name = new ResourceName();
   1240     if (!assetmanager.GetResourceName(resid, name)) {
   1241       return null;
   1242     }
   1243 
   1244     if (name.entry != null) {
   1245       return name.entry;
   1246     // } else if (name.entry16 != null) {
   1247     //   return name.entry16; // env.NewString(reinterpret_cast<jchar*>(name.entry16), name.entry_len);
   1248     }
   1249     return null;
   1250   }
   1251 
   1252   // static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
   1253 //                                      jboolean exclude_system) {
   1254   @Implementation(minSdk = P)
   1255   protected static @Nullable String[] nativeGetLocales(long ptr, boolean exclude_system) {
   1256     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1257     Set<String> locales =
   1258         assetmanager.GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
   1259 
   1260     String[] array = new String[locales.size()]; // env.NewObjectArray(locales.size(), g_stringClass, null);
   1261     // if (array == null) {
   1262     //   return null;
   1263     // }
   1264 
   1265     int idx = 0;
   1266     for (String locale : locales) {
   1267       String java_string = locale;
   1268       if (java_string == null) {
   1269         return null;
   1270       }
   1271       // env.SetObjectArrayElement(array, idx++, java_string);
   1272       array[idx++] = java_string;
   1273       // env.DeleteLocalRef(java_string);
   1274     }
   1275     return array;
   1276   }
   1277 
   1278   static Configuration ConstructConfigurationObject(/* JNIEnv* env,*/ ResTable_config config) {
   1279     // jobject result =
   1280     //     env.NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
   1281     Configuration result = new Configuration();
   1282     // if (result == null) {
   1283     //   return null;
   1284     // }
   1285 
   1286     result.smallestScreenWidthDp = config.smallestScreenWidthDp;
   1287     result.screenWidthDp = config.screenWidthDp;
   1288     result.screenHeightDp = config.screenHeightDp;
   1289     return result;
   1290   }
   1291 
   1292   // static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
   1293   @Implementation(minSdk = P)
   1294   protected static @Nullable Configuration[] nativeGetSizeConfigurations(long ptr) {
   1295     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1296     Set<ResTable_config> configurations =
   1297         assetmanager.GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
   1298 
   1299     Configuration[] array = new Configuration[configurations.size()];
   1300     // env.NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, null);
   1301     // if (array == null) {
   1302     //   return null;
   1303     // }
   1304 
   1305     int idx = 0;
   1306     for (ResTable_config configuration : configurations) {
   1307       Configuration java_configuration = ConstructConfigurationObject(configuration);
   1308       // if (java_configuration == null) {
   1309       //   return null;
   1310       // }
   1311 
   1312       // env.SetObjectArrayElement(array, idx++, java_configuration);
   1313       array[idx++] = java_configuration;
   1314       // env.DeleteLocalRef(java_configuration);
   1315     }
   1316     return array;
   1317   }
   1318 
   1319   // static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1320 //                              jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
   1321 //                              jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
   1322   @Implementation(minSdk = P)
   1323   protected static void nativeApplyStyle(long ptr, long theme_ptr, @AttrRes int def_style_attr,
   1324       @StyleRes int def_style_resid, long xml_parser_ptr, @NonNull int[] java_attrs,
   1325       long out_values_ptr, long out_indices_ptr) {
   1326     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1327     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1328     CHECK(theme.GetAssetManager() == assetmanager);
   1329     // (void) assetmanager;
   1330 
   1331     ResXMLParser xml_parser =
   1332         xml_parser_ptr == 0 ? null : NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr);
   1333     // int[] out_values = reinterpret_cast<int*>(out_values_ptr);
   1334     // int[] out_indices = reinterpret_cast<int*>(out_indices_ptr);
   1335     ShadowVMRuntime shadowVMRuntime = Shadow.extract(VMRuntime.getRuntime());
   1336     int[] out_values = (int[])shadowVMRuntime.getObjectForAddress(out_values_ptr);
   1337     int[] out_indices = (int[])shadowVMRuntime.getObjectForAddress(out_indices_ptr);
   1338 
   1339     int attrs_len = java_attrs.length;
   1340     int[] attrs = java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
   1341     // if (attrs == null) {
   1342     //   return;
   1343     // }
   1344 
   1345     ApplyStyle(theme, xml_parser, (int) (def_style_attr),
   1346         (int) (def_style_resid), attrs, attrs_len,
   1347         out_values, out_indices);
   1348     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1349   }
   1350 
   1351   // static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1352 //                                    jint def_style_attr, jint def_style_resid, jintArray java_values,
   1353 //                                    jintArray java_attrs, jintArray out_java_values,
   1354 //                                    jintArray out_java_indices) {
   1355   @Implementation(minSdk = P)
   1356   protected static boolean nativeResolveAttrs(long ptr, long theme_ptr,
   1357       @AttrRes int def_style_attr, @StyleRes int def_style_resid, @Nullable int[] java_values,
   1358       @NonNull int[] java_attrs, @NonNull int[] out_java_values, @NonNull int[] out_java_indices) {
   1359     int attrs_len = java_attrs.length;
   1360     int out_values_len = out_java_values.length;
   1361     if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
   1362       throw new IndexOutOfBoundsException("outValues too small");
   1363     }
   1364 
   1365     int[] attrs = java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
   1366     if (attrs == null) {
   1367       return JNI_FALSE;
   1368     }
   1369 
   1370     int[] values = null;
   1371     int values_len = 0;
   1372     if (java_values != null) {
   1373       values_len = java_values.length;
   1374       values = java_values; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_values, null));
   1375       if (values == null) {
   1376         // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1377         return JNI_FALSE;
   1378       }
   1379     }
   1380 
   1381     int[] out_values = out_java_values;
   1382     // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null));
   1383     if (out_values == null) {
   1384       // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1385       // if (values != null) {
   1386       //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1387       // }
   1388       return JNI_FALSE;
   1389     }
   1390 
   1391     int[] out_indices = null;
   1392     if (out_java_indices != null) {
   1393       int out_indices_len = out_java_indices.length;
   1394       if (out_indices_len > attrs_len) {
   1395         out_indices = out_java_indices;
   1396         // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null));
   1397         if (out_indices == null) {
   1398           // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1399           // if (values != null) {
   1400           //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1401           // }
   1402           // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
   1403           return JNI_FALSE;
   1404         }
   1405       }
   1406     }
   1407 
   1408     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1409     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1410     CHECK(theme.GetAssetManager() == assetmanager);
   1411     // (void) assetmanager;
   1412 
   1413     boolean result = ResolveAttrs(
   1414         theme, (int) (def_style_attr), (int) (def_style_resid),
   1415         values, values_len, attrs,
   1416         attrs_len, out_values, out_indices);
   1417     // if (out_indices != null) {
   1418     //   env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
   1419     // }
   1420 
   1421     // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
   1422     // if (values != null) {
   1423     //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
   1424     // }
   1425     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1426     return result ? JNI_TRUE : JNI_FALSE;
   1427   }
   1428 
   1429   // static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
   1430 //                                          jlong xml_parser_ptr, jintArray java_attrs,
   1431 //                                          jintArray out_java_values, jintArray out_java_indices) {
   1432   @Implementation(minSdk = P)
   1433   protected static boolean nativeRetrieveAttributes(long ptr, long xml_parser_ptr,
   1434       @NonNull int[] java_attrs, @NonNull int[] out_java_values, @NonNull int[] out_java_indices) {
   1435     int attrs_len = java_attrs.length;
   1436     int out_values_len = out_java_values.length;
   1437     if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
   1438       throw new IndexOutOfBoundsException("outValues too small");
   1439     }
   1440 
   1441     int[] attrs = java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
   1442     if (attrs == null) {
   1443       return JNI_FALSE;
   1444     }
   1445 
   1446     int[] out_values = out_java_values;
   1447     // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null));
   1448     if (out_values == null) {
   1449       // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1450       return JNI_FALSE;
   1451     }
   1452 
   1453     int[] out_indices = null;
   1454     if (out_java_indices != null) {
   1455       int out_indices_len = out_java_indices.length;
   1456       if (out_indices_len > attrs_len) {
   1457         out_indices = out_java_indices;
   1458         // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null));
   1459         if (out_indices == null) {
   1460           // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1461           // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
   1462           return JNI_FALSE;
   1463         }
   1464       }
   1465     }
   1466 
   1467     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1468     ResXMLParser xml_parser = NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr);
   1469 
   1470     boolean result = RetrieveAttributes(assetmanager, xml_parser,
   1471         attrs, attrs_len,
   1472         out_values,
   1473         out_indices);
   1474 
   1475     // if (out_indices != null) {
   1476     //   env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
   1477     // }
   1478     // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
   1479     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
   1480     return result;
   1481   }
   1482 
   1483   // static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
   1484   @Implementation(minSdk = P)
   1485   protected static long nativeThemeCreate(long ptr) {
   1486     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1487     return Registries.NATIVE_THEME9_REGISTRY.register(assetmanager.NewTheme());
   1488   }
   1489 
   1490   // static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
   1491   @Implementation(minSdk = P)
   1492   protected static void nativeThemeDestroy(long theme_ptr) {
   1493     Registries.NATIVE_THEME9_REGISTRY.unregister(theme_ptr);
   1494   }
   1495 
   1496   // static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1497 //                                   jint resid, jboolean force) {
   1498   @Implementation(minSdk = P)
   1499   protected static void nativeThemeApplyStyle(long ptr, long theme_ptr, @StyleRes int resid,
   1500       boolean force) {
   1501     // AssetManager is accessed via the theme, so grab an explicit lock here.
   1502     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1503     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1504     CHECK(theme.GetAssetManager() == assetmanager);
   1505     // (void) assetmanager;
   1506     theme.ApplyStyle(resid, force);
   1507 
   1508     // TODO(adamlesinski): Consider surfacing exception when result is failure.
   1509     // CTS currently expects no exceptions from this method.
   1510     // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
   1511     // throw new IllegalArgumentException(error_msg.c_str());
   1512   }
   1513 
   1514   // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
   1515 //                             jlong src_theme_ptr) {
   1516   @Implementation(minSdk = P, maxSdk = P)
   1517   protected static void nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr) {
   1518     Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr);
   1519     Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr);
   1520     if (!dst_theme.SetTo(src_theme)) {
   1521       throw new IllegalArgumentException("Themes are from different AssetManagers");
   1522     }
   1523   }
   1524 
   1525   // BEGIN-INTERNAL
   1526   // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
   1527   //     jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
   1528   @Implementation(minSdk = Q)
   1529   protected static void nativeThemeCopy(
   1530       long dst_asset_manager_ptr,
   1531       long dst_theme_ptr,
   1532       long src_asset_manager_ptr,
   1533       long src_theme_ptr) {
   1534     Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr);
   1535     Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr);
   1536     if (dst_asset_manager_ptr != src_asset_manager_ptr) {
   1537       CppAssetManager2 dst_assetmanager = AssetManagerFromLong(dst_asset_manager_ptr);
   1538       CHECK(dst_theme.GetAssetManager() == dst_assetmanager);
   1539       // (void) dst_assetmanager;
   1540 
   1541       CppAssetManager2 src_assetmanager = AssetManagerFromLong(src_asset_manager_ptr);
   1542       CHECK(src_theme.GetAssetManager() == src_assetmanager);
   1543       // (void) src_assetmanager;
   1544 
   1545       dst_theme.SetTo(src_theme);
   1546     } else {
   1547       dst_theme.SetTo(src_theme);
   1548     }
   1549   }
   1550   // END-INTERNAL
   1551 
   1552   // static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
   1553   @Implementation(minSdk = P)
   1554   protected static void nativeThemeClear(long themePtr) {
   1555     Registries.NATIVE_THEME9_REGISTRY.getNativeObject(themePtr).Clear();
   1556   }
   1557 
   1558   // static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1559 //                                          jint resid, jobject typed_value,
   1560 //                                          jboolean resolve_references) {
   1561   @Implementation(minSdk = P)
   1562   protected static int nativeThemeGetAttributeValue(long ptr, long theme_ptr,
   1563       @AttrRes int resid, @NonNull TypedValue typed_value, boolean resolve_references) {
   1564     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1565     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1566     CHECK(theme.GetAssetManager() == assetmanager);
   1567     // (void) assetmanager; // huh?
   1568 
   1569     final Ref<Res_value> value = new Ref<>(null);
   1570     final Ref<Integer> flags = new Ref<>(null);
   1571     ApkAssetsCookie cookie = theme.GetAttribute(resid, value, flags);
   1572     if (cookie.intValue() == kInvalidCookie) {
   1573       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
   1574     }
   1575 
   1576     final Ref<Integer> ref = new Ref<>(0);
   1577     if (resolve_references) {
   1578       final Ref<ResTable_config> selected_config = new Ref<>(null);
   1579       cookie =
   1580           theme.GetAssetManager().ResolveReference(cookie, value, selected_config, flags, ref);
   1581       if (cookie.intValue() == kInvalidCookie) {
   1582         return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
   1583       }
   1584     }
   1585     return CopyValue(cookie, value.get(), ref.get(), flags.get(), null, typed_value);
   1586   }
   1587 
   1588   // static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
   1589 //                             jint priority, jstring tag, jstring prefix) {
   1590   @Implementation(minSdk = P)
   1591   protected static void nativeThemeDump(long ptr, long theme_ptr, int priority, String tag,
   1592       String prefix) {
   1593     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
   1594     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1595     CHECK(theme.GetAssetManager() == assetmanager);
   1596     // (void) assetmanager;
   1597     // (void) theme;
   1598     // (void) priority;
   1599     // (void) tag;
   1600     // (void) prefix;
   1601   }
   1602 
   1603   // static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
   1604 //                                                  jlong theme_ptr) {
   1605   @Implementation(minSdk = P)
   1606   protected static @NativeConfig int nativeThemeGetChangingConfigurations(long theme_ptr) {
   1607     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
   1608     return (int) (theme.GetChangingConfigurations());
   1609   }
   1610 
   1611   // static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1612   @Implementation(minSdk = P)
   1613   protected static void nativeAssetDestroy(long asset_ptr) {
   1614     Registries.NATIVE_ASSET_REGISTRY.unregister(asset_ptr);
   1615   }
   1616 
   1617   // static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1618   @Implementation(minSdk = P)
   1619   protected static int nativeAssetReadChar(long asset_ptr) {
   1620     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
   1621     byte[] b = new byte[1];
   1622     int res = asset.read(b, 1);
   1623     return res == 1 ? (int) (b[0]) & 0xff : -1;
   1624   }
   1625 
   1626   // static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
   1627 //                             jint offset, jint len) {
   1628   @Implementation(minSdk = P)
   1629   protected static int nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)
   1630       throws IOException {
   1631     if (len == 0) {
   1632       return 0;
   1633     }
   1634 
   1635     int buffer_len = java_buffer.length;
   1636     if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
   1637         offset > buffer_len - len) {
   1638       throw new IndexOutOfBoundsException();
   1639     }
   1640 
   1641     // ScopedByteArrayRW byte_array(env, java_buffer);
   1642     // if (byte_array.get() == null) {
   1643     //   return -1;
   1644     // }
   1645 
   1646     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
   1647     // sint res = asset.read(byte_array.get() + offset, len);
   1648     int res = asset.read(java_buffer, offset, len);
   1649     if (res < 0) {
   1650       throw new IOException();
   1651     }
   1652     return res > 0 ? (int) (res) : -1;
   1653   }
   1654 
   1655   // static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
   1656 //                              jint whence) {
   1657   @Implementation(minSdk = P)
   1658   protected static long nativeAssetSeek(long asset_ptr, long offset, int whence) {
   1659     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
   1660     return asset.seek(
   1661         (offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR)));
   1662   }
   1663 
   1664   // static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1665   @Implementation(minSdk = P)
   1666   protected static long nativeAssetGetLength(long asset_ptr) {
   1667     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
   1668     return asset.getLength();
   1669   }
   1670 
   1671   // static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
   1672   @Implementation(minSdk = P)
   1673   protected static long nativeAssetGetRemainingLength(long asset_ptr) {
   1674     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
   1675     return asset.getRemainingLength();
   1676   }
   1677 
   1678 // ----------------------------------------------------------------------------
   1679 
   1680   // JNI registration.
   1681   // static JNINativeMethod gAssetManagerMethods[] = {
   1682   //     // AssetManager setup methods.
   1683   //     {"nativeCreate", "()J", (void*)NativeCreate},
   1684   //   {"nativeDestroy", "(J)V", (void*)NativeDestroy},
   1685   //   {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
   1686   //   {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
   1687   //   (void*)NativeSetConfiguration},
   1688   //   {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
   1689   //   (void*)NativeGetAssignedPackageIdentifiers},
   1690   //
   1691   //   // AssetManager file methods.
   1692   //   {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
   1693   //   {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
   1694   //   {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1695   //   (void*)NativeOpenAssetFd},
   1696   //   {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
   1697   //   {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1698   //   (void*)NativeOpenNonAssetFd},
   1699   //   {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
   1700   //
   1701   //   // AssetManager resource methods.
   1702   //   {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
   1703   //   {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
   1704   //   (void*)NativeGetResourceBagValue},
   1705   //   {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
   1706   //   {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
   1707   //   (void*)NativeGetResourceStringArray},
   1708   //   {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
   1709   //   {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
   1710   //   {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
   1711   //   {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
   1712   //
   1713   //   // AssetManager resource name/ID methods.
   1714   //   {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
   1715   //   (void*)NativeGetResourceIdentifier},
   1716   //   {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
   1717   //   {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
   1718   //   {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
   1719   //   {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
   1720   //   {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
   1721   //   {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
   1722   //   (void*)NativeGetSizeConfigurations},
   1723   //
   1724   //   // Style attribute related methods.
   1725   //   {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
   1726   //   {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
   1727   //   {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
   1728   //
   1729   //   // Theme related methods.
   1730   //   {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
   1731   //   {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
   1732   //   {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
   1733   //   {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
   1734   //   {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
   1735   //   {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
   1736   //   (void*)NativeThemeGetAttributeValue},
   1737   //   {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
   1738   //   {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
   1739   //
   1740   //   // AssetInputStream methods.
   1741   //   {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
   1742   //   {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
   1743   //   {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
   1744   //   {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
   1745   //   {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
   1746   //   {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
   1747   //
   1748   //   // System/idmap related methods.
   1749   //   {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
   1750   //
   1751   //   // Global management/debug methods.
   1752   //   {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
   1753   //   {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
   1754   //   {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
   1755   //   };
   1756   //
   1757   //   int register_android_content_AssetManager(JNIEnv* env) {
   1758   //   jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
   1759   //   gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
   1760   //
   1761   //   jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
   1762   //   gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
   1763   //   gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
   1764   //   gTypedValueOffsets.mString =
   1765   //   GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
   1766   //   gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
   1767   //   gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
   1768   //   gTypedValueOffsets.mChangingConfigurations =
   1769   //   GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
   1770   //   gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
   1771   //
   1772   //   jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
   1773   //   gAssetFileDescriptorOffsets.mFd =
   1774   //   GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
   1775   //   gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
   1776   //   gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
   1777   //
   1778   //   jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
   1779   //   gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
   1780   //
   1781   //   jclass stringClass = FindClassOrDie(env, "java/lang/String");
   1782   //   g_stringClass = MakeGlobalRefOrDie(env, stringClass);
   1783   //
   1784   //   jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
   1785   //   gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
   1786   //   gSparseArrayOffsets.constructor =
   1787   //   GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
   1788   //   gSparseArrayOffsets.put =
   1789   //   GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
   1790   //
   1791   //   jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
   1792   //   gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
   1793   //   gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
   1794   //   gConfigurationOffsets.mSmallestScreenWidthDpOffset =
   1795   //   GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
   1796   //   gConfigurationOffsets.mScreenWidthDpOffset =
   1797   //   GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
   1798   //   gConfigurationOffsets.mScreenHeightDpOffset =
   1799   //   GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
   1800   //
   1801   //   return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
   1802   //   NELEM(gAssetManagerMethods));
   1803   //   }
   1804 
   1805 }; // namespace android
   1806