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