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