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