• 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.StyleRes;
30 import android.content.res.ApkAssets;
31 import android.content.res.AssetManager;
32 import android.content.res.Configuration;
33 import android.content.res.Configuration.NativeConfig;
34 import android.os.Build;
35 import android.os.ParcelFileDescriptor;
36 import android.util.SparseArray;
37 import android.util.TypedValue;
38 import com.google.common.annotations.VisibleForTesting;
39 import dalvik.system.VMRuntime;
40 import java.io.File;
41 import java.io.FileDescriptor;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.List;
49 import java.util.Set;
50 import javax.annotation.Nonnull;
51 import javax.annotation.Nullable;
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     return PerfStatsCollector.getInstance()
868         .measure(
869             "binary nativeGetResourceValue",
870             () -> {
871               CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
872               final Ref<Res_value> value = new Ref<>(null);
873               final Ref<ResTable_config> selected_config = new Ref<>(null);
874               final Ref<Integer> flags = new Ref<>(0);
875               ApkAssetsCookie cookie =
876                   assetmanager.GetResource(
877                       resid,
878                       false /*may_be_bag*/,
879                       (short) (density),
880                       value,
881                       selected_config,
882                       flags);
883               if (cookie.intValue() == kInvalidCookie) {
884                 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
885               }
886 
887               final Ref<Integer> ref = new Ref<>(resid);
888               if (resolve_references) {
889                 cookie = assetmanager.ResolveReference(cookie, value, selected_config, flags, ref);
890                 if (cookie.intValue() == kInvalidCookie) {
891                   return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
892                 }
893               }
894               return CopyValue(
895                   cookie, value.get(), ref.get(), flags.get(), selected_config.get(), typed_value);
896             });
897   }
898 
899   // static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
900   //                                       jint bag_entry_id, jobject typed_value) {
901   @Implementation(minSdk = P)
nativeGetResourceBagValue( long ptr, @AnyRes int resid, int bag_entry_id, @Nonnull TypedValue typed_value)902   protected static int nativeGetResourceBagValue(
903       long ptr, @AnyRes int resid, int bag_entry_id, @Nonnull TypedValue typed_value) {
904     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
905     ResolvedBag bag = assetmanager.GetBag(resid);
906     if (bag == null) {
907       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
908     }
909 
910     final Ref<Integer> type_spec_flags = new Ref<>(bag.type_spec_flags);
911     ApkAssetsCookie cookie = K_INVALID_COOKIE;
912     Res_value bag_value = null;
913     for (ResolvedBag.Entry entry : bag.entries) {
914       if (entry.key == (int) (bag_entry_id)) {
915         cookie = entry.cookie;
916         bag_value = entry.value;
917 
918         // Keep searching (the old implementation did that).
919       }
920     }
921 
922     if (cookie.intValue() == kInvalidCookie) {
923       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
924     }
925 
926     final Ref<Res_value> value = new Ref<>(bag_value);
927     final Ref<Integer> ref = new Ref<>(resid);
928     final Ref<ResTable_config> selected_config = new Ref<>(null);
929     cookie = assetmanager.ResolveReference(cookie, value, selected_config, type_spec_flags, ref);
930     if (cookie.intValue() == kInvalidCookie) {
931       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
932     }
933     return CopyValue(cookie, value.get(), ref.get(), type_spec_flags.get(), null, typed_value);
934   }
935 
936   // static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid)
937   // {
938   @Implementation(minSdk = P)
nativeGetStyleAttributes( long ptr, @StyleRes int resid)939   protected static @Nullable @AttrRes int[] nativeGetStyleAttributes(
940       long ptr, @StyleRes int resid) {
941     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
942     ResolvedBag bag = assetmanager.GetBag(resid);
943     if (bag == null) {
944       return null;
945     }
946 
947     int[] array = new int[bag.entry_count];
948     // if (env.ExceptionCheck()) {
949     //   return null;
950     // }
951 
952     for (int i = 0; i < bag.entry_count; i++) {
953       int attr_resid = bag.entries[i].key;
954       // env.SetIntArrayRegion(array, i, 1, &attr_resid);
955       array[i] = attr_resid;
956     }
957     return array;
958   }
959 
960   // static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
961   //                                                  jint resid) {
962   @Implementation(minSdk = P)
nativeGetResourceStringArray(long ptr, @ArrayRes int resid)963   protected static @Nullable String[] nativeGetResourceStringArray(long ptr, @ArrayRes int resid) {
964     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
965     ResolvedBag bag = assetmanager.GetBag(resid);
966     if (bag == null) {
967       return null;
968     }
969 
970     String[] array = new String[bag.entry_count];
971     if (array == null) {
972       return null;
973     }
974 
975     for (int i = 0; i < bag.entry_count; i++) {
976       ResolvedBag.Entry entry = bag.entries[i];
977 
978       // Resolve any references to their final value.
979       final Ref<Res_value> value = new Ref<>(entry.value);
980       final Ref<ResTable_config> selected_config = new Ref<>(null);
981       final Ref<Integer> flags = new Ref<>(0);
982       final Ref<Integer> ref = new Ref<>(0);
983       ApkAssetsCookie cookie =
984           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
985       if (cookie.intValue() == kInvalidCookie) {
986         return null;
987       }
988 
989       if (value.get().dataType == Res_value.TYPE_STRING) {
990         CppApkAssets apk_assets = assetmanager.GetApkAssets().get(cookie.intValue());
991         ResStringPool pool = apk_assets.GetLoadedArsc().GetStringPool();
992 
993         String java_string = null;
994         String str_utf8 = pool.stringAt(value.get().data);
995         if (str_utf8 != null) {
996           java_string = str_utf8;
997         } else {
998           String str_utf16 = pool.stringAt(value.get().data);
999           java_string = str_utf16;
1000         }
1001 
1002         // // Check for errors creating the strings (if malformed or no memory).
1003         // if (env.ExceptionCheck()) {
1004         //   return null;
1005         // }
1006 
1007         // env.SetObjectArrayElement(array, i, java_string);
1008         array[i] = java_string;
1009 
1010         // If we have a large amount of string in our array, we might overflow the
1011         // local reference table of the VM.
1012         // env.DeleteLocalRef(java_string);
1013       }
1014     }
1015     return array;
1016   }
1017 
1018   // static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1019   //                                                   jint resid) {
1020   @Implementation(minSdk = P)
nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resid)1021   protected static @Nullable int[] nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resid) {
1022     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1023     ResolvedBag bag = assetmanager.GetBag(resid);
1024     if (bag == null) {
1025       return null;
1026     }
1027 
1028     int[] array = new int[bag.entry_count * 2];
1029     // if (array == null) {
1030     //   return null;
1031     // }
1032 
1033     int[] buffer = array; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null));
1034     // if (buffer == null) {
1035     //   return null;
1036     // }
1037 
1038     for (int i = 0; i < bag.entry_count; i++) {
1039       ResolvedBag.Entry entry = bag.entries[i];
1040       final Ref<Res_value> value = new Ref<>(entry.value);
1041       final Ref<ResTable_config> selected_config = new Ref<>(null);
1042       final Ref<Integer> flags = new Ref<>(0);
1043       final Ref<Integer> ref = new Ref<>(0);
1044       ApkAssetsCookie cookie =
1045           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
1046       if (cookie.intValue() == kInvalidCookie) {
1047         // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
1048         return null;
1049       }
1050 
1051       int string_index = -1;
1052       if (value.get().dataType == Res_value.TYPE_STRING) {
1053         string_index = (int) (value.get().data);
1054       }
1055 
1056       buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
1057       buffer[(i * 2) + 1] = string_index;
1058     }
1059     // env.ReleasePrimitiveArrayCritical(array, buffer, 0);
1060     return array;
1061   }
1062 
1063   // static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint
1064   // resid) {
1065   @Implementation(minSdk = P)
nativeGetResourceIntArray(long ptr, @ArrayRes int resid)1066   protected static @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resid) {
1067     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1068     ResolvedBag bag = assetmanager.GetBag(resid);
1069     if (bag == null) {
1070       return null;
1071     }
1072 
1073     int[] array = new int[bag.entry_count];
1074     // if (array == null) {
1075     //   return null;
1076     // }
1077 
1078     int[] buffer = array; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null));
1079     // if (buffer == null) {
1080     //   return null;
1081     // }
1082 
1083     for (int i = 0; i < bag.entry_count; i++) {
1084       ResolvedBag.Entry entry = bag.entries[i];
1085       final Ref<Res_value> value = new Ref<>(entry.value);
1086       final Ref<ResTable_config> selected_config = new Ref<>(null);
1087       final Ref<Integer> flags = new Ref<>(0);
1088       final Ref<Integer> ref = new Ref<>(0);
1089       ApkAssetsCookie cookie =
1090           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
1091       if (cookie.intValue() == kInvalidCookie) {
1092         // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
1093         return null;
1094       }
1095 
1096       if (value.get().dataType >= Res_value.TYPE_FIRST_INT
1097           && value.get().dataType <= Res_value.TYPE_LAST_INT) {
1098         buffer[i] = (int) (value.get().data);
1099       }
1100     }
1101     // env.ReleasePrimitiveArrayCritical(array, buffer, 0);
1102     return array;
1103   }
1104 
1105   // static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint
1106   // resid) {
1107   @Implementation(minSdk = P)
nativeGetResourceArraySize(long ptr, @ArrayRes int resid)1108   protected static int nativeGetResourceArraySize(long ptr, @ArrayRes int resid) {
1109     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1110     ResolvedBag bag = assetmanager.GetBag(resid);
1111     if (bag == null) {
1112       return -1;
1113     }
1114     return (int) (bag.entry_count);
1115   }
1116 
1117   // static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
1118   //                                    jintArray out_data) {
1119   @Implementation(minSdk = P)
nativeGetResourceArray( long ptr, @ArrayRes int resid, @Nonnull int[] out_data)1120   protected static int nativeGetResourceArray(
1121       long ptr, @ArrayRes int resid, @Nonnull int[] out_data) {
1122     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1123     ResolvedBag bag = assetmanager.GetBag(resid);
1124     if (bag == null) {
1125       return -1;
1126     }
1127 
1128     int out_data_length = out_data.length;
1129     // if (env.ExceptionCheck()) {
1130     //   return -1;
1131     // }
1132 
1133     if ((int) (bag.entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
1134       throw new IllegalArgumentException("Input array is not large enough");
1135     }
1136 
1137     int[] buffer =
1138         out_data; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_data, null));
1139     if (buffer == null) {
1140       return -1;
1141     }
1142 
1143     int[] cursor = buffer;
1144     for (int i = 0; i < bag.entry_count; i++) {
1145       ResolvedBag.Entry entry = bag.entries[i];
1146       final Ref<Res_value> value = new Ref<>(entry.value);
1147       final Ref<ResTable_config> selected_config = new Ref<>(new ResTable_config());
1148       selected_config.get().density = 0;
1149       final Ref<Integer> flags = new Ref<>(bag.type_spec_flags);
1150       final Ref<Integer> ref = new Ref<>(0);
1151       ApkAssetsCookie cookie =
1152           assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref);
1153       if (cookie.intValue() == kInvalidCookie) {
1154         // env.ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
1155         return -1;
1156       }
1157 
1158       // Deal with the special @null value -- it turns back to TYPE_NULL.
1159       if (value.get().dataType == Res_value.TYPE_REFERENCE && value.get().data == 0) {
1160         value.set(Res_value.NULL_VALUE);
1161       }
1162 
1163       int offset = i * STYLE_NUM_ENTRIES;
1164       cursor[offset + STYLE_TYPE] = (int) (value.get().dataType);
1165       cursor[offset + STYLE_DATA] = (int) (value.get().data);
1166       cursor[offset + STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
1167       cursor[offset + STYLE_RESOURCE_ID] = (int) (ref.get());
1168       cursor[offset + STYLE_CHANGING_CONFIGURATIONS] = (int) (flags.get());
1169       cursor[offset + STYLE_DENSITY] = (int) (selected_config.get().density);
1170       // cursor += STYLE_NUM_ENTRIES;
1171     }
1172     // env.ReleasePrimitiveArrayCritical(out_data, buffer, 0);
1173     return (int) (bag.entry_count);
1174   }
1175 
1176   // static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
1177   //                                         jstring def_type, jstring def_package) {
1178   @Implementation(minSdk = P)
nativeGetResourceIdentifier( long ptr, @Nonnull String name, @Nullable String def_type, @Nullable String def_package)1179   protected static @AnyRes int nativeGetResourceIdentifier(
1180       long ptr, @Nonnull String name, @Nullable String def_type, @Nullable String def_package) {
1181     String name_utf8 = name;
1182     if (name_utf8 == null) {
1183       // This will throw NPE.
1184       return 0;
1185     }
1186 
1187     String type = null;
1188     if (def_type != null) {
1189       String type_utf8 = def_type;
1190       CHECK(type_utf8 != null);
1191       type = type_utf8;
1192     }
1193 
1194     String package_ = null;
1195     if (def_package != null) {
1196       String package_utf8 = def_package;
1197       CHECK(package_utf8 != null);
1198       package_ = package_utf8;
1199     }
1200     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1201     return (int) (assetmanager.GetResourceId(name_utf8, type, package_));
1202   }
1203 
1204   // static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1205   @Implementation(minSdk = P)
nativeGetResourceName(long ptr, @AnyRes int resid)1206   protected static @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid) {
1207     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1208     CppAssetManager2.ResourceName name = new ResourceName();
1209     if (!assetmanager.GetResourceName(resid, name)) {
1210       return null;
1211     }
1212 
1213     StringBuilder result = new StringBuilder();
1214     if (name.package_ != null) {
1215       result.append(name.package_ /*, name.package_len*/);
1216     }
1217 
1218     if (name.type != null /*|| name.type16 != null*/) {
1219       if (!(result.length() == 0)) {
1220         result.append(":");
1221       }
1222 
1223       // if (name.type != null) {
1224       result.append(name.type /*, name.type_len*/);
1225       // } else {
1226       //   result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.type16 /*, name.type_len))*/);
1227       // }
1228     }
1229 
1230     if (name.entry != null /*|| name.entry16 != null*/) {
1231       if (!(result.length() == 0)) {
1232         result.append("/");
1233       }
1234 
1235       // if (name.entry != null) {
1236       result.append(name.entry /*, name.entry_len*/);
1237       // } else {
1238       //   result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.entry16 /*, name.entry_len)*/);
1239       // }
1240     }
1241     return result.toString();
1242   }
1243 
1244   // static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint
1245   // resid) {
1246   @Implementation(minSdk = P)
nativeGetResourcePackageName(long ptr, @AnyRes int resid)1247   protected static @Nullable String nativeGetResourcePackageName(long ptr, @AnyRes int resid) {
1248     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1249     final ResourceName name = new ResourceName();
1250     if (!assetmanager.GetResourceName(resid, name)) {
1251       return null;
1252     }
1253 
1254     if (name.package_ != null) {
1255       return name.package_;
1256     }
1257     return null;
1258   }
1259 
1260   // static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid)
1261   // {
1262   @Implementation(minSdk = P)
nativeGetResourceTypeName(long ptr, @AnyRes int resid)1263   protected static @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid) {
1264     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1265     final ResourceName name = new ResourceName();
1266     if (!assetmanager.GetResourceName(resid, name)) {
1267       return null;
1268     }
1269 
1270     if (name.type != null) {
1271       return name.type;
1272       // } else if (name.get().type16 != null) {
1273       //   return name.get().type16; // env.NewString(reinterpret_cast<jchar*>(name.type16),
1274       // name.type_len);
1275     }
1276     return null;
1277   }
1278 
1279   // static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid)
1280   // {
1281   @Implementation(minSdk = P)
nativeGetResourceEntryName(long ptr, @AnyRes int resid)1282   protected static @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid) {
1283     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1284     final ResourceName name = new ResourceName();
1285     if (!assetmanager.GetResourceName(resid, name)) {
1286       return null;
1287     }
1288 
1289     if (name.entry != null) {
1290       return name.entry;
1291       // } else if (name.entry16 != null) {
1292       //   return name.entry16; // env.NewString(reinterpret_cast<jchar*>(name.entry16),
1293       // name.entry_len);
1294     }
1295     return null;
1296   }
1297 
1298   // static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
1299   //                                      jboolean exclude_system) {
1300   @Implementation(minSdk = P)
nativeGetLocales(long ptr, boolean exclude_system)1301   protected static @Nullable String[] nativeGetLocales(long ptr, boolean exclude_system) {
1302     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1303     Set<String> locales =
1304         assetmanager.GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
1305 
1306     String[] array =
1307         new String[locales.size()]; // env.NewObjectArray(locales.size(), g_stringClass, null);
1308     // if (array == null) {
1309     //   return null;
1310     // }
1311 
1312     int idx = 0;
1313     for (String locale : locales) {
1314       String java_string = locale;
1315       if (java_string == null) {
1316         return null;
1317       }
1318       // env.SetObjectArrayElement(array, idx++, java_string);
1319       array[idx++] = java_string;
1320       // env.DeleteLocalRef(java_string);
1321     }
1322     return array;
1323   }
1324 
ConstructConfigurationObject( ResTable_config config)1325   static Configuration ConstructConfigurationObject(/* JNIEnv* env,*/ ResTable_config config) {
1326     // jobject result =
1327     //     env.NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1328     Configuration result = new Configuration();
1329     // if (result == null) {
1330     //   return null;
1331     // }
1332 
1333     result.smallestScreenWidthDp = config.smallestScreenWidthDp;
1334     result.screenWidthDp = config.screenWidthDp;
1335     result.screenHeightDp = config.screenHeightDp;
1336     return result;
1337   }
1338 
1339   // static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1340   @Implementation(minSdk = P)
nativeGetSizeConfigurations(long ptr)1341   protected static @Nullable Configuration[] nativeGetSizeConfigurations(long ptr) {
1342     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1343     Set<ResTable_config> configurations =
1344         assetmanager.GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1345 
1346     Configuration[] array = new Configuration[configurations.size()];
1347     // env.NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, null);
1348     // if (array == null) {
1349     //   return null;
1350     // }
1351 
1352     int idx = 0;
1353     for (ResTable_config configuration : configurations) {
1354       Configuration java_configuration = ConstructConfigurationObject(configuration);
1355       // if (java_configuration == null) {
1356       //   return null;
1357       // }
1358 
1359       // env.SetObjectArrayElement(array, idx++, java_configuration);
1360       array[idx++] = java_configuration;
1361       // env.DeleteLocalRef(java_configuration);
1362     }
1363     return array;
1364   }
1365 
1366   // static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1367   //                              jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1368   //                              jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr)
1369   // {
1370   @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)1371   protected static void nativeApplyStyle(
1372       long ptr,
1373       long theme_ptr,
1374       @AttrRes int def_style_attr,
1375       @StyleRes int def_style_resid,
1376       long xml_parser_ptr,
1377       @Nonnull int[] java_attrs,
1378       long out_values_ptr,
1379       long out_indices_ptr) {
1380     PerfStatsCollector.getInstance()
1381         .measure(
1382             "applyStyle",
1383             () ->
1384                 nativeApplyStyle_measured(
1385                     ptr,
1386                     theme_ptr,
1387                     def_style_attr,
1388                     def_style_resid,
1389                     xml_parser_ptr,
1390                     java_attrs,
1391                     out_values_ptr,
1392                     out_indices_ptr));
1393   }
1394 
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)1395   private static void nativeApplyStyle_measured(
1396       long ptr,
1397       long theme_ptr,
1398       @AttrRes int def_style_attr,
1399       @StyleRes int def_style_resid,
1400       long xml_parser_ptr,
1401       @Nonnull int[] java_attrs,
1402       long out_values_ptr,
1403       long out_indices_ptr) {
1404     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1405     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1406     CHECK(theme.GetAssetManager() == assetmanager);
1407     // (void) assetmanager;
1408 
1409     ResXMLParser xml_parser =
1410         xml_parser_ptr == 0 ? null : NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr);
1411     // int[] out_values = reinterpret_cast<int*>(out_values_ptr);
1412     // int[] out_indices = reinterpret_cast<int*>(out_indices_ptr);
1413     ShadowVMRuntime shadowVMRuntime = Shadow.extract(VMRuntime.getRuntime());
1414     int[] out_values = (int[]) shadowVMRuntime.getObjectForAddress(out_values_ptr);
1415     int[] out_indices = (int[]) shadowVMRuntime.getObjectForAddress(out_indices_ptr);
1416 
1417     int attrs_len = java_attrs.length;
1418     int[] attrs =
1419         java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
1420     // if (attrs == null) {
1421     //   return;
1422     // }
1423 
1424     ApplyStyle(
1425         theme,
1426         xml_parser,
1427         (int) (def_style_attr),
1428         (int) (def_style_resid),
1429         attrs,
1430         attrs_len,
1431         out_values,
1432         out_indices);
1433     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1434   }
1435 
1436   // static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1437   //                                    jint def_style_attr, jint def_style_resid, jintArray
1438   // java_values,
1439   //                                    jintArray java_attrs, jintArray out_java_values,
1440   //                                    jintArray out_java_indices) {
1441   @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)1442   protected static boolean nativeResolveAttrs(
1443       long ptr,
1444       long theme_ptr,
1445       @AttrRes int def_style_attr,
1446       @StyleRes int def_style_resid,
1447       @Nullable int[] java_values,
1448       @Nonnull int[] java_attrs,
1449       @Nonnull int[] out_java_values,
1450       @Nonnull int[] out_java_indices) {
1451     int attrs_len = java_attrs.length;
1452     int out_values_len = out_java_values.length;
1453     if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1454       throw new IndexOutOfBoundsException("outValues too small");
1455     }
1456 
1457     int[] attrs =
1458         java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
1459     if (attrs == null) {
1460       return JNI_FALSE;
1461     }
1462 
1463     int[] values = null;
1464     int values_len = 0;
1465     if (java_values != null) {
1466       values_len = java_values.length;
1467       values =
1468           java_values; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_values, null));
1469       if (values == null) {
1470         // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1471         return JNI_FALSE;
1472       }
1473     }
1474 
1475     int[] out_values = out_java_values;
1476     // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null));
1477     if (out_values == null) {
1478       // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1479       // if (values != null) {
1480       //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1481       // }
1482       return JNI_FALSE;
1483     }
1484 
1485     int[] out_indices = null;
1486     if (out_java_indices != null) {
1487       int out_indices_len = out_java_indices.length;
1488       if (out_indices_len > attrs_len) {
1489         out_indices = out_java_indices;
1490         // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null));
1491         if (out_indices == null) {
1492           // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1493           // if (values != null) {
1494           //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1495           // }
1496           // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1497           return JNI_FALSE;
1498         }
1499       }
1500     }
1501 
1502     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1503     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1504     CHECK(theme.GetAssetManager() == assetmanager);
1505     // (void) assetmanager;
1506 
1507     boolean result =
1508         ResolveAttrs(
1509             theme,
1510             (int) (def_style_attr),
1511             (int) (def_style_resid),
1512             values,
1513             values_len,
1514             attrs,
1515             attrs_len,
1516             out_values,
1517             out_indices);
1518     // if (out_indices != null) {
1519     //   env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1520     // }
1521 
1522     // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1523     // if (values != null) {
1524     //   env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1525     // }
1526     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1527     return result ? JNI_TRUE : JNI_FALSE;
1528   }
1529 
1530   // static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1531   //                                          jlong xml_parser_ptr, jintArray java_attrs,
1532   //                                          jintArray out_java_values, jintArray out_java_indices)
1533   // {
1534   @Implementation(minSdk = P)
nativeRetrieveAttributes( long ptr, long xml_parser_ptr, @Nonnull int[] java_attrs, @Nonnull int[] out_java_values, @Nonnull int[] out_java_indices)1535   protected static boolean nativeRetrieveAttributes(
1536       long ptr,
1537       long xml_parser_ptr,
1538       @Nonnull int[] java_attrs,
1539       @Nonnull int[] out_java_values,
1540       @Nonnull int[] out_java_indices) {
1541     int attrs_len = java_attrs.length;
1542     int out_values_len = out_java_values.length;
1543     if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1544       throw new IndexOutOfBoundsException("outValues too small");
1545     }
1546 
1547     int[] attrs =
1548         java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null));
1549     if (attrs == null) {
1550       return JNI_FALSE;
1551     }
1552 
1553     int[] out_values = out_java_values;
1554     // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null));
1555     if (out_values == null) {
1556       // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1557       return JNI_FALSE;
1558     }
1559 
1560     int[] out_indices = null;
1561     if (out_java_indices != null) {
1562       int out_indices_len = out_java_indices.length;
1563       if (out_indices_len > attrs_len) {
1564         out_indices = out_java_indices;
1565         // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null));
1566         if (out_indices == null) {
1567           // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1568           // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1569           return JNI_FALSE;
1570         }
1571       }
1572     }
1573 
1574     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1575     ResXMLParser xml_parser = NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr);
1576 
1577     boolean result =
1578         RetrieveAttributes(assetmanager, xml_parser, attrs, attrs_len, out_values, out_indices);
1579 
1580     // if (out_indices != null) {
1581     //   env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1582     // }
1583     // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1584     // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1585     return result;
1586   }
1587 
1588   // static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1589   @Implementation(minSdk = P)
nativeThemeCreate(long ptr)1590   protected static long nativeThemeCreate(long ptr) {
1591     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1592     return Registries.NATIVE_THEME9_REGISTRY.register(assetmanager.NewTheme());
1593   }
1594 
1595   // static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1596   @Implementation(minSdk = P, maxSdk = R)
nativeThemeDestroy(long theme_ptr)1597   protected static void nativeThemeDestroy(long theme_ptr) {
1598     Registries.NATIVE_THEME9_REGISTRY.unregister(theme_ptr);
1599   }
1600 
1601   @Implementation(minSdk = S)
releaseTheme(long ptr)1602   protected void releaseTheme(long ptr) {
1603     Registries.NATIVE_THEME9_REGISTRY.unregister(ptr);
1604     reflector(AssetManagerReflector.class, realAssetManager).releaseTheme(ptr);
1605   }
1606 
1607   // static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1608   //                                   jint resid, jboolean force) {
1609   @Implementation(minSdk = P)
nativeThemeApplyStyle( long ptr, long theme_ptr, @StyleRes int resid, boolean force)1610   protected static void nativeThemeApplyStyle(
1611       long ptr, long theme_ptr, @StyleRes int resid, boolean force) {
1612     // AssetManager is accessed via the theme, so grab an explicit lock here.
1613     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1614     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1615     CHECK(theme.GetAssetManager() == assetmanager);
1616     // (void) assetmanager;
1617     theme.ApplyStyle(resid, force);
1618 
1619     // TODO(adamlesinski): Consider surfacing exception when result is failure.
1620     // CTS currently expects no exceptions from this method.
1621     // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1622     // throw new IllegalArgumentException(error_msg.c_str());
1623   }
1624 
1625   // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
1626   //                             jlong src_theme_ptr) {
1627   @Implementation(minSdk = P, maxSdk = P)
nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr)1628   protected static void nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr) {
1629     Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr);
1630     Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr);
1631     if (!dst_theme.SetTo(src_theme)) {
1632       throw new IllegalArgumentException("Themes are from different AssetManagers");
1633     }
1634   }
1635 
1636   // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1637   //     jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
1638   @Implementation(minSdk = Q)
nativeThemeCopy( long dst_asset_manager_ptr, long dst_theme_ptr, long src_asset_manager_ptr, long src_theme_ptr)1639   protected static void nativeThemeCopy(
1640       long dst_asset_manager_ptr,
1641       long dst_theme_ptr,
1642       long src_asset_manager_ptr,
1643       long src_theme_ptr) {
1644     Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr);
1645     Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr);
1646     if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1647       CppAssetManager2 dst_assetmanager = AssetManagerFromLong(dst_asset_manager_ptr);
1648       CHECK(dst_theme.GetAssetManager() == dst_assetmanager);
1649       // (void) dst_assetmanager;
1650 
1651       CppAssetManager2 src_assetmanager = AssetManagerFromLong(src_asset_manager_ptr);
1652       CHECK(src_theme.GetAssetManager() == src_assetmanager);
1653       // (void) src_assetmanager;
1654 
1655       dst_theme.SetTo(src_theme);
1656     } else {
1657       dst_theme.SetTo(src_theme);
1658     }
1659   }
1660 
1661   // static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1662   @Implementation(minSdk = P, maxSdk = R)
nativeThemeClear(long themePtr)1663   protected static void nativeThemeClear(long themePtr) {
1664     Registries.NATIVE_THEME9_REGISTRY.getNativeObject(themePtr).Clear();
1665   }
1666 
1667   // static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong
1668   // theme_ptr,
1669   //                                          jint resid, jobject typed_value,
1670   //                                          jboolean resolve_references) {
1671   @Implementation(minSdk = P)
nativeThemeGetAttributeValue( long ptr, long theme_ptr, @AttrRes int resid, @Nonnull TypedValue typed_value, boolean resolve_references)1672   protected static int nativeThemeGetAttributeValue(
1673       long ptr,
1674       long theme_ptr,
1675       @AttrRes int resid,
1676       @Nonnull TypedValue typed_value,
1677       boolean resolve_references) {
1678     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1679     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1680     CHECK(theme.GetAssetManager() == assetmanager);
1681     // (void) assetmanager; // huh?
1682 
1683     final Ref<Res_value> value = new Ref<>(null);
1684     final Ref<Integer> flags = new Ref<>(null);
1685     ApkAssetsCookie cookie = theme.GetAttribute(resid, value, flags);
1686     if (cookie.intValue() == kInvalidCookie) {
1687       return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
1688     }
1689 
1690     final Ref<Integer> ref = new Ref<>(0);
1691     if (resolve_references) {
1692       final Ref<ResTable_config> selected_config = new Ref<>(null);
1693       cookie = theme.GetAssetManager().ResolveReference(cookie, value, selected_config, flags, ref);
1694       if (cookie.intValue() == kInvalidCookie) {
1695         return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE);
1696       }
1697     }
1698     return CopyValue(cookie, value.get(), ref.get(), flags.get(), null, typed_value);
1699   }
1700 
1701   // static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1702   //                             jint priority, jstring tag, jstring prefix) {
1703   @Implementation(minSdk = P)
nativeThemeDump( long ptr, long theme_ptr, int priority, String tag, String prefix)1704   protected static void nativeThemeDump(
1705       long ptr, long theme_ptr, int priority, String tag, String prefix) {
1706     CppAssetManager2 assetmanager = AssetManagerFromLong(ptr);
1707     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1708     CHECK(theme.GetAssetManager() == assetmanager);
1709     // (void) assetmanager;
1710     // (void) theme;
1711     // (void) priority;
1712     // (void) tag;
1713     // (void) prefix;
1714   }
1715 
1716   // static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1717   //                                                  jlong theme_ptr) {
1718   @Implementation(minSdk = P)
nativeThemeGetChangingConfigurations(long theme_ptr)1719   protected static @NativeConfig int nativeThemeGetChangingConfigurations(long theme_ptr) {
1720     Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr);
1721     return (int) (theme.GetChangingConfigurations());
1722   }
1723 
1724   // static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1725   @Implementation(minSdk = P)
nativeAssetDestroy(long asset_ptr)1726   protected static void nativeAssetDestroy(long asset_ptr) {
1727     Registries.NATIVE_ASSET_REGISTRY.unregister(asset_ptr);
1728   }
1729 
1730   // static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1731   @Implementation(minSdk = P)
nativeAssetReadChar(long asset_ptr)1732   protected static int nativeAssetReadChar(long asset_ptr) {
1733     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
1734     byte[] b = new byte[1];
1735     int res = asset.read(b, 1);
1736     return res == 1 ? (int) (b[0]) & 0xff : -1;
1737   }
1738 
1739   // static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray
1740   // java_buffer,
1741   //                             jint offset, jint len) {
1742   @Implementation(minSdk = P)
nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)1743   protected static int nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)
1744       throws IOException {
1745     if (len == 0) {
1746       return 0;
1747     }
1748 
1749     int buffer_len = java_buffer.length;
1750     if (offset < 0
1751         || offset >= buffer_len
1752         || len < 0
1753         || len > buffer_len
1754         || offset > buffer_len - len) {
1755       throw new IndexOutOfBoundsException();
1756     }
1757 
1758     // ScopedByteArrayRW byte_array(env, java_buffer);
1759     // if (byte_array.get() == null) {
1760     //   return -1;
1761     // }
1762 
1763     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
1764     // sint res = asset.read(byte_array.get() + offset, len);
1765     int res = asset.read(java_buffer, offset, len);
1766     if (res < 0) {
1767       throw new IOException();
1768     }
1769     return res > 0 ? (int) (res) : -1;
1770   }
1771 
1772   // static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1773   //                              jint whence) {
1774   @Implementation(minSdk = P)
nativeAssetSeek(long asset_ptr, long offset, int whence)1775   protected static long nativeAssetSeek(long asset_ptr, long offset, int whence) {
1776     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
1777     return asset.seek((offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR)));
1778   }
1779 
1780   // static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1781   @Implementation(minSdk = P)
nativeAssetGetLength(long asset_ptr)1782   protected static long nativeAssetGetLength(long asset_ptr) {
1783     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
1784     return asset.getLength();
1785   }
1786 
1787   // static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr)
1788   // {
1789   @Implementation(minSdk = P)
nativeAssetGetRemainingLength(long asset_ptr)1790   protected static long nativeAssetGetRemainingLength(long asset_ptr) {
1791     Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr);
1792     return asset.getRemainingLength();
1793   }
1794 
1795   // ----------------------------------------------------------------------------
1796 
1797   // JNI registration.
1798   // static JNINativeMethod gAssetManagerMethods[] = {
1799   //     // AssetManager setup methods.
1800   //     {"nativeCreate", "()J", (void*)NativeCreate},
1801   //   {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1802   //   {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1803   //   {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1804   //   (void*)NativeSetConfiguration},
1805   //   {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
1806   //   (void*)NativeGetAssignedPackageIdentifiers},
1807   //
1808   //   // AssetManager file methods.
1809   //   {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1810   //   {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1811   //   {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1812   //   (void*)NativeOpenAssetFd},
1813   //   {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1814   //   {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1815   //   (void*)NativeOpenNonAssetFd},
1816   //   {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
1817   //
1818   //   // AssetManager resource methods.
1819   //   {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I",
1820   // (void*)NativeGetResourceValue},
1821   //   {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1822   //   (void*)NativeGetResourceBagValue},
1823   //   {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1824   //   {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1825   //   (void*)NativeGetResourceStringArray},
1826   //   {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1827   //   {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1828   //   {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1829   //   {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1830   //
1831   //   // AssetManager resource name/ID methods.
1832   //   {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1833   //   (void*)NativeGetResourceIdentifier},
1834   //   {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1835   //   {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;",
1836   // (void*)NativeGetResourcePackageName},
1837   //   {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1838   //   {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
1839   //   {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1840   //   {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1841   //   (void*)NativeGetSizeConfigurations},
1842   //
1843   //   // Style attribute related methods.
1844   //   {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1845   //   {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1846   //   {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1847   //
1848   //   // Theme related methods.
1849   //   {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1850   //   {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1851   //   {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
1852   //   {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
1853   //   {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1854   //   {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1855   //   (void*)NativeThemeGetAttributeValue},
1856   //   {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1857   //   {"nativeThemeGetChangingConfigurations", "(J)I",
1858   // (void*)NativeThemeGetChangingConfigurations},
1859   //
1860   //   // AssetInputStream methods.
1861   //   {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1862   //   {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1863   //   {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1864   //   {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1865   //   {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1866   //   {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1867   //
1868   //   // System/idmap related methods.
1869   //   {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
1870   //
1871   //   // Global management/debug methods.
1872   //   {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1873   //   {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1874   //   {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1875   //   };
1876   //
1877   //   int register_android_content_AssetManager(JNIEnv* env) {
1878   //   jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1879   //   gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1880   //
1881   //   jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1882   //   gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1883   //   gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1884   //   gTypedValueOffsets.mString =
1885   //   GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1886   //   gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1887   //   gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1888   //   gTypedValueOffsets.mChangingConfigurations =
1889   //   GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1890   //   gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1891   //
1892   //   jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1893   //   gAssetFileDescriptorOffsets.mFd =
1894   //   GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1895   //   gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset",
1896   // "J");
1897   //   gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1898   //
1899   //   jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1900   //   gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1901   //
1902   //   jclass stringClass = FindClassOrDie(env, "java/lang/String");
1903   //   g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1904   //
1905   //   jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1906   //   gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1907   //   gSparseArrayOffsets.constructor =
1908   //   GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1909   //   gSparseArrayOffsets.put =
1910   //   GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1911   //
1912   //   jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1913   //   gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1914   //   gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>",
1915   // "()V");
1916   //   gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1917   //   GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1918   //   gConfigurationOffsets.mScreenWidthDpOffset =
1919   //   GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1920   //   gConfigurationOffsets.mScreenHeightDpOffset =
1921   //   GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1922   //
1923   //   return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1924   //   NELEM(gAssetManagerMethods));
1925   //   }
1926 
1927   @ForType(AssetManager.class)
1928   interface AssetManagerReflector {
1929 
1930     @Static
1931     @Direct
createSystemAssetsInZygoteLocked()1932     void createSystemAssetsInZygoteLocked();
1933 
1934     @Direct
releaseTheme(long ptr)1935     void releaseTheme(long ptr);
1936   }
1937 }
1938 // namespace android
1939