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