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