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