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