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