• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
createSystemAssetsInZygoteLocked()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
reset()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.
ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie)244     static int ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
245         return cookie.intValue() != kInvalidCookie ? (cookie.intValue() + 1) : -1;
246     }
247 
JavaCookieToApkAssetsCookie(int cookie)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)
nativeVerifySystemIdmaps()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)
nativeCreateIdmapsForStaticOverlaysTargetingAndroid()345     protected static String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid() {
346         return new String[0];
347     }
348 
CopyValue( ApkAssetsCookie cookie, Res_value value, int ref, int type_spec_flags, ResTable_config config, TypedValue out_typed_value)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
getAllAssetDirs()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
getAssetPaths()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 
NdkAssetManagerForJavaObject( AssetManager jassetmanager)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 
AssetManagerForJavaObject( AssetManager jassetmanager)409     static CppAssetManager2 AssetManagerForJavaObject(/* JNIEnv* env,*/ AssetManager jassetmanager) {
410         return NdkAssetManagerForJavaObject(jassetmanager);
411     }
412 
AssetManagerFromLong(long ptr)413     static CppAssetManager2 AssetManagerFromLong(long ptr) {
414         // return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager>(ptr));
415         return Registries.NATIVE_ASSET_MANAGER_REGISTRY.getNativeObject(ptr);
416     }
417 
ReturnParcelFileDescriptor( Asset asset, long[] out_offsets)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)
__constructor__(boolean sentinel)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)
getGlobalAssetCount()469     protected static int getGlobalAssetCount() {
470         return Asset.getGlobalCount();
471     }
472 
473     // static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
474     @Implementation(minSdk = P)
getAssetAllocations()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)
getGlobalAssetManagerCount()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)
nativeCreate()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)
nativeDestroy(long ptr)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)
nativeSetApkAssets(long ptr, @NonNull android.content.res.ApkAssets[] apk_assets_array, boolean invalidate_caches)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)
nativeSetConfiguration(long ptr, int mcc, int mnc, @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, int keyboard_hidden, int navigation, int screen_width, int screen_height, int smallest_screen_width_dp, int screen_width_dp, int screen_height_dp, int screen_layout, int ui_mode, int color_mode, int major_version)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)
nativeGetAssignedPackageIdentifiers( long ptr)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)
nativeList(long ptr, @NonNull String path)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)
nativeOpenAsset(long ptr, @NonNull String asset_path, int access_mode)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)
nativeOpenAssetFd(long ptr, @NonNull String asset_path, long[] out_offsets)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)
nativeOpenNonAsset(long ptr, int jcookie, @NonNull String asset_path, int access_mode)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)
nativeOpenNonAssetFd(long ptr, int jcookie, @NonNull String asset_path, @NonNull long[] out_offsets)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)
nativeOpenXmlAsset(long ptr, int jcookie, @NonNull String asset_path)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)
nativeGetResourceValue(long ptr, @AnyRes int resid, short density, @NonNull TypedValue typed_value, boolean resolve_references)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)
nativeGetResourceBagValue(long ptr, @AnyRes int resid, int bag_entry_id, @NonNull TypedValue typed_value)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)
nativeGetStyleAttributes(long ptr, @StyleRes int resid)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)
nativeGetResourceStringArray(long ptr, @ArrayRes int resid)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)
nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resid)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)
nativeGetResourceIntArray(long ptr, @ArrayRes int resid)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)
nativeGetResourceArraySize(long ptr, @ArrayRes int resid)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)
nativeGetResourceArray(long ptr, @ArrayRes int resid, @NonNull int[] out_data)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)
nativeGetResourceIdentifier(long ptr, @NonNull String name, @Nullable String def_type, @Nullable String def_package)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)
nativeGetResourceName(long ptr, @AnyRes int resid)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)
nativeGetResourcePackageName(long ptr, @AnyRes int resid)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)
nativeGetResourceTypeName(long ptr, @AnyRes int resid)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)
nativeGetResourceEntryName(long ptr, @AnyRes int resid)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)
nativeGetLocales(long ptr, boolean exclude_system)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 
ConstructConfigurationObject( ResTable_config config)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)
nativeGetSizeConfigurations(long ptr)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)
nativeApplyStyle(long ptr, long theme_ptr, @AttrRes int def_style_attr, @StyleRes int def_style_resid, long xml_parser_ptr, @NonNull int[] java_attrs, long out_values_ptr, long out_indices_ptr)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)
nativeResolveAttrs(long ptr, long theme_ptr, @AttrRes int def_style_attr, @StyleRes int def_style_resid, @Nullable int[] java_values, @NonNull int[] java_attrs, @NonNull int[] out_java_values, @NonNull int[] out_java_indices)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)
nativeRetrieveAttributes(long ptr, long xml_parser_ptr, @NonNull int[] java_attrs, @NonNull int[] out_java_values, @NonNull int[] out_java_indices)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)
nativeThemeCreate(long ptr)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)
nativeThemeDestroy(long theme_ptr)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)
nativeThemeApplyStyle(long ptr, long theme_ptr, @StyleRes int resid, boolean force)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)
nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr)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)
nativeThemeCopy( long dst_asset_manager_ptr, long dst_theme_ptr, long src_asset_manager_ptr, long src_theme_ptr)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)
nativeThemeClear(long themePtr)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)
nativeThemeGetAttributeValue(long ptr, long theme_ptr, @AttrRes int resid, @NonNull TypedValue typed_value, boolean resolve_references)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)
nativeThemeDump(long ptr, long theme_ptr, int priority, String tag, String prefix)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)
nativeThemeGetChangingConfigurations(long theme_ptr)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)
nativeAssetDestroy(long asset_ptr)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)
nativeAssetReadChar(long asset_ptr)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)
nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)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)
nativeAssetSeek(long asset_ptr, long offset, int whence)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)
nativeAssetGetLength(long asset_ptr)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)
nativeAssetGetRemainingLength(long asset_ptr)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