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.StyleRes; 30 import android.content.res.ApkAssets; 31 import android.content.res.AssetManager; 32 import android.content.res.Configuration; 33 import android.content.res.Configuration.NativeConfig; 34 import android.os.Build; 35 import android.os.ParcelFileDescriptor; 36 import android.util.SparseArray; 37 import android.util.TypedValue; 38 import com.google.common.annotations.VisibleForTesting; 39 import dalvik.system.VMRuntime; 40 import java.io.File; 41 import java.io.FileDescriptor; 42 import java.io.FileNotFoundException; 43 import java.io.IOException; 44 import java.nio.file.Path; 45 import java.nio.file.Paths; 46 import java.util.ArrayList; 47 import java.util.Collection; 48 import java.util.List; 49 import java.util.Set; 50 import javax.annotation.Nonnull; 51 import javax.annotation.Nullable; 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 return PerfStatsCollector.getInstance() 868 .measure( 869 "binary nativeGetResourceValue", 870 () -> { 871 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 872 final Ref<Res_value> value = new Ref<>(null); 873 final Ref<ResTable_config> selected_config = new Ref<>(null); 874 final Ref<Integer> flags = new Ref<>(0); 875 ApkAssetsCookie cookie = 876 assetmanager.GetResource( 877 resid, 878 false /*may_be_bag*/, 879 (short) (density), 880 value, 881 selected_config, 882 flags); 883 if (cookie.intValue() == kInvalidCookie) { 884 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 885 } 886 887 final Ref<Integer> ref = new Ref<>(resid); 888 if (resolve_references) { 889 cookie = assetmanager.ResolveReference(cookie, value, selected_config, flags, ref); 890 if (cookie.intValue() == kInvalidCookie) { 891 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 892 } 893 } 894 return CopyValue( 895 cookie, value.get(), ref.get(), flags.get(), selected_config.get(), typed_value); 896 }); 897 } 898 899 // static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid, 900 // jint bag_entry_id, jobject typed_value) { 901 @Implementation(minSdk = P) nativeGetResourceBagValue( long ptr, @AnyRes int resid, int bag_entry_id, @Nonnull TypedValue typed_value)902 protected static int nativeGetResourceBagValue( 903 long ptr, @AnyRes int resid, int bag_entry_id, @Nonnull TypedValue typed_value) { 904 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 905 ResolvedBag bag = assetmanager.GetBag(resid); 906 if (bag == null) { 907 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 908 } 909 910 final Ref<Integer> type_spec_flags = new Ref<>(bag.type_spec_flags); 911 ApkAssetsCookie cookie = K_INVALID_COOKIE; 912 Res_value bag_value = null; 913 for (ResolvedBag.Entry entry : bag.entries) { 914 if (entry.key == (int) (bag_entry_id)) { 915 cookie = entry.cookie; 916 bag_value = entry.value; 917 918 // Keep searching (the old implementation did that). 919 } 920 } 921 922 if (cookie.intValue() == kInvalidCookie) { 923 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 924 } 925 926 final Ref<Res_value> value = new Ref<>(bag_value); 927 final Ref<Integer> ref = new Ref<>(resid); 928 final Ref<ResTable_config> selected_config = new Ref<>(null); 929 cookie = assetmanager.ResolveReference(cookie, value, selected_config, type_spec_flags, ref); 930 if (cookie.intValue() == kInvalidCookie) { 931 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 932 } 933 return CopyValue(cookie, value.get(), ref.get(), type_spec_flags.get(), null, typed_value); 934 } 935 936 // static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) 937 // { 938 @Implementation(minSdk = P) nativeGetStyleAttributes( long ptr, @StyleRes int resid)939 protected static @Nullable @AttrRes int[] nativeGetStyleAttributes( 940 long ptr, @StyleRes int resid) { 941 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 942 ResolvedBag bag = assetmanager.GetBag(resid); 943 if (bag == null) { 944 return null; 945 } 946 947 int[] array = new int[bag.entry_count]; 948 // if (env.ExceptionCheck()) { 949 // return null; 950 // } 951 952 for (int i = 0; i < bag.entry_count; i++) { 953 int attr_resid = bag.entries[i].key; 954 // env.SetIntArrayRegion(array, i, 1, &attr_resid); 955 array[i] = attr_resid; 956 } 957 return array; 958 } 959 960 // static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, 961 // jint resid) { 962 @Implementation(minSdk = P) nativeGetResourceStringArray(long ptr, @ArrayRes int resid)963 protected static @Nullable String[] nativeGetResourceStringArray(long ptr, @ArrayRes int resid) { 964 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 965 ResolvedBag bag = assetmanager.GetBag(resid); 966 if (bag == null) { 967 return null; 968 } 969 970 String[] array = new String[bag.entry_count]; 971 if (array == null) { 972 return null; 973 } 974 975 for (int i = 0; i < bag.entry_count; i++) { 976 ResolvedBag.Entry entry = bag.entries[i]; 977 978 // Resolve any references to their final value. 979 final Ref<Res_value> value = new Ref<>(entry.value); 980 final Ref<ResTable_config> selected_config = new Ref<>(null); 981 final Ref<Integer> flags = new Ref<>(0); 982 final Ref<Integer> ref = new Ref<>(0); 983 ApkAssetsCookie cookie = 984 assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref); 985 if (cookie.intValue() == kInvalidCookie) { 986 return null; 987 } 988 989 if (value.get().dataType == Res_value.TYPE_STRING) { 990 CppApkAssets apk_assets = assetmanager.GetApkAssets().get(cookie.intValue()); 991 ResStringPool pool = apk_assets.GetLoadedArsc().GetStringPool(); 992 993 String java_string = null; 994 String str_utf8 = pool.stringAt(value.get().data); 995 if (str_utf8 != null) { 996 java_string = str_utf8; 997 } else { 998 String str_utf16 = pool.stringAt(value.get().data); 999 java_string = str_utf16; 1000 } 1001 1002 // // Check for errors creating the strings (if malformed or no memory). 1003 // if (env.ExceptionCheck()) { 1004 // return null; 1005 // } 1006 1007 // env.SetObjectArrayElement(array, i, java_string); 1008 array[i] = java_string; 1009 1010 // If we have a large amount of string in our array, we might overflow the 1011 // local reference table of the VM. 1012 // env.DeleteLocalRef(java_string); 1013 } 1014 } 1015 return array; 1016 } 1017 1018 // static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr, 1019 // jint resid) { 1020 @Implementation(minSdk = P) nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resid)1021 protected static @Nullable int[] nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resid) { 1022 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1023 ResolvedBag bag = assetmanager.GetBag(resid); 1024 if (bag == null) { 1025 return null; 1026 } 1027 1028 int[] array = new int[bag.entry_count * 2]; 1029 // if (array == null) { 1030 // return null; 1031 // } 1032 1033 int[] buffer = array; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null)); 1034 // if (buffer == null) { 1035 // return null; 1036 // } 1037 1038 for (int i = 0; i < bag.entry_count; i++) { 1039 ResolvedBag.Entry entry = bag.entries[i]; 1040 final Ref<Res_value> value = new Ref<>(entry.value); 1041 final Ref<ResTable_config> selected_config = new Ref<>(null); 1042 final Ref<Integer> flags = new Ref<>(0); 1043 final Ref<Integer> ref = new Ref<>(0); 1044 ApkAssetsCookie cookie = 1045 assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref); 1046 if (cookie.intValue() == kInvalidCookie) { 1047 // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT); 1048 return null; 1049 } 1050 1051 int string_index = -1; 1052 if (value.get().dataType == Res_value.TYPE_STRING) { 1053 string_index = (int) (value.get().data); 1054 } 1055 1056 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie); 1057 buffer[(i * 2) + 1] = string_index; 1058 } 1059 // env.ReleasePrimitiveArrayCritical(array, buffer, 0); 1060 return array; 1061 } 1062 1063 // static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint 1064 // resid) { 1065 @Implementation(minSdk = P) nativeGetResourceIntArray(long ptr, @ArrayRes int resid)1066 protected static @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resid) { 1067 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1068 ResolvedBag bag = assetmanager.GetBag(resid); 1069 if (bag == null) { 1070 return null; 1071 } 1072 1073 int[] array = new int[bag.entry_count]; 1074 // if (array == null) { 1075 // return null; 1076 // } 1077 1078 int[] buffer = array; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(array, null)); 1079 // if (buffer == null) { 1080 // return null; 1081 // } 1082 1083 for (int i = 0; i < bag.entry_count; i++) { 1084 ResolvedBag.Entry entry = bag.entries[i]; 1085 final Ref<Res_value> value = new Ref<>(entry.value); 1086 final Ref<ResTable_config> selected_config = new Ref<>(null); 1087 final Ref<Integer> flags = new Ref<>(0); 1088 final Ref<Integer> ref = new Ref<>(0); 1089 ApkAssetsCookie cookie = 1090 assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref); 1091 if (cookie.intValue() == kInvalidCookie) { 1092 // env.ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT); 1093 return null; 1094 } 1095 1096 if (value.get().dataType >= Res_value.TYPE_FIRST_INT 1097 && value.get().dataType <= Res_value.TYPE_LAST_INT) { 1098 buffer[i] = (int) (value.get().data); 1099 } 1100 } 1101 // env.ReleasePrimitiveArrayCritical(array, buffer, 0); 1102 return array; 1103 } 1104 1105 // static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint 1106 // resid) { 1107 @Implementation(minSdk = P) nativeGetResourceArraySize(long ptr, @ArrayRes int resid)1108 protected static int nativeGetResourceArraySize(long ptr, @ArrayRes int resid) { 1109 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1110 ResolvedBag bag = assetmanager.GetBag(resid); 1111 if (bag == null) { 1112 return -1; 1113 } 1114 return (int) (bag.entry_count); 1115 } 1116 1117 // static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid, 1118 // jintArray out_data) { 1119 @Implementation(minSdk = P) nativeGetResourceArray( long ptr, @ArrayRes int resid, @Nonnull int[] out_data)1120 protected static int nativeGetResourceArray( 1121 long ptr, @ArrayRes int resid, @Nonnull int[] out_data) { 1122 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1123 ResolvedBag bag = assetmanager.GetBag(resid); 1124 if (bag == null) { 1125 return -1; 1126 } 1127 1128 int out_data_length = out_data.length; 1129 // if (env.ExceptionCheck()) { 1130 // return -1; 1131 // } 1132 1133 if ((int) (bag.entry_count) > out_data_length * STYLE_NUM_ENTRIES) { 1134 throw new IllegalArgumentException("Input array is not large enough"); 1135 } 1136 1137 int[] buffer = 1138 out_data; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_data, null)); 1139 if (buffer == null) { 1140 return -1; 1141 } 1142 1143 int[] cursor = buffer; 1144 for (int i = 0; i < bag.entry_count; i++) { 1145 ResolvedBag.Entry entry = bag.entries[i]; 1146 final Ref<Res_value> value = new Ref<>(entry.value); 1147 final Ref<ResTable_config> selected_config = new Ref<>(new ResTable_config()); 1148 selected_config.get().density = 0; 1149 final Ref<Integer> flags = new Ref<>(bag.type_spec_flags); 1150 final Ref<Integer> ref = new Ref<>(0); 1151 ApkAssetsCookie cookie = 1152 assetmanager.ResolveReference(entry.cookie, value, selected_config, flags, ref); 1153 if (cookie.intValue() == kInvalidCookie) { 1154 // env.ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT); 1155 return -1; 1156 } 1157 1158 // Deal with the special @null value -- it turns back to TYPE_NULL. 1159 if (value.get().dataType == Res_value.TYPE_REFERENCE && value.get().data == 0) { 1160 value.set(Res_value.NULL_VALUE); 1161 } 1162 1163 int offset = i * STYLE_NUM_ENTRIES; 1164 cursor[offset + STYLE_TYPE] = (int) (value.get().dataType); 1165 cursor[offset + STYLE_DATA] = (int) (value.get().data); 1166 cursor[offset + STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie); 1167 cursor[offset + STYLE_RESOURCE_ID] = (int) (ref.get()); 1168 cursor[offset + STYLE_CHANGING_CONFIGURATIONS] = (int) (flags.get()); 1169 cursor[offset + STYLE_DENSITY] = (int) (selected_config.get().density); 1170 // cursor += STYLE_NUM_ENTRIES; 1171 } 1172 // env.ReleasePrimitiveArrayCritical(out_data, buffer, 0); 1173 return (int) (bag.entry_count); 1174 } 1175 1176 // static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name, 1177 // jstring def_type, jstring def_package) { 1178 @Implementation(minSdk = P) nativeGetResourceIdentifier( long ptr, @Nonnull String name, @Nullable String def_type, @Nullable String def_package)1179 protected static @AnyRes int nativeGetResourceIdentifier( 1180 long ptr, @Nonnull String name, @Nullable String def_type, @Nullable String def_package) { 1181 String name_utf8 = name; 1182 if (name_utf8 == null) { 1183 // This will throw NPE. 1184 return 0; 1185 } 1186 1187 String type = null; 1188 if (def_type != null) { 1189 String type_utf8 = def_type; 1190 CHECK(type_utf8 != null); 1191 type = type_utf8; 1192 } 1193 1194 String package_ = null; 1195 if (def_package != null) { 1196 String package_utf8 = def_package; 1197 CHECK(package_utf8 != null); 1198 package_ = package_utf8; 1199 } 1200 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1201 return (int) (assetmanager.GetResourceId(name_utf8, type, package_)); 1202 } 1203 1204 // static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) { 1205 @Implementation(minSdk = P) nativeGetResourceName(long ptr, @AnyRes int resid)1206 protected static @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid) { 1207 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1208 CppAssetManager2.ResourceName name = new ResourceName(); 1209 if (!assetmanager.GetResourceName(resid, name)) { 1210 return null; 1211 } 1212 1213 StringBuilder result = new StringBuilder(); 1214 if (name.package_ != null) { 1215 result.append(name.package_ /*, name.package_len*/); 1216 } 1217 1218 if (name.type != null /*|| name.type16 != null*/) { 1219 if (!(result.length() == 0)) { 1220 result.append(":"); 1221 } 1222 1223 // if (name.type != null) { 1224 result.append(name.type /*, name.type_len*/); 1225 // } else { 1226 // result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.type16 /*, name.type_len))*/); 1227 // } 1228 } 1229 1230 if (name.entry != null /*|| name.entry16 != null*/) { 1231 if (!(result.length() == 0)) { 1232 result.append("/"); 1233 } 1234 1235 // if (name.entry != null) { 1236 result.append(name.entry /*, name.entry_len*/); 1237 // } else { 1238 // result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.entry16 /*, name.entry_len)*/); 1239 // } 1240 } 1241 return result.toString(); 1242 } 1243 1244 // static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint 1245 // resid) { 1246 @Implementation(minSdk = P) nativeGetResourcePackageName(long ptr, @AnyRes int resid)1247 protected static @Nullable String nativeGetResourcePackageName(long ptr, @AnyRes int resid) { 1248 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1249 final ResourceName name = new ResourceName(); 1250 if (!assetmanager.GetResourceName(resid, name)) { 1251 return null; 1252 } 1253 1254 if (name.package_ != null) { 1255 return name.package_; 1256 } 1257 return null; 1258 } 1259 1260 // static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) 1261 // { 1262 @Implementation(minSdk = P) nativeGetResourceTypeName(long ptr, @AnyRes int resid)1263 protected static @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid) { 1264 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1265 final ResourceName name = new ResourceName(); 1266 if (!assetmanager.GetResourceName(resid, name)) { 1267 return null; 1268 } 1269 1270 if (name.type != null) { 1271 return name.type; 1272 // } else if (name.get().type16 != null) { 1273 // return name.get().type16; // env.NewString(reinterpret_cast<jchar*>(name.type16), 1274 // name.type_len); 1275 } 1276 return null; 1277 } 1278 1279 // static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) 1280 // { 1281 @Implementation(minSdk = P) nativeGetResourceEntryName(long ptr, @AnyRes int resid)1282 protected static @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid) { 1283 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1284 final ResourceName name = new ResourceName(); 1285 if (!assetmanager.GetResourceName(resid, name)) { 1286 return null; 1287 } 1288 1289 if (name.entry != null) { 1290 return name.entry; 1291 // } else if (name.entry16 != null) { 1292 // return name.entry16; // env.NewString(reinterpret_cast<jchar*>(name.entry16), 1293 // name.entry_len); 1294 } 1295 return null; 1296 } 1297 1298 // static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr, 1299 // jboolean exclude_system) { 1300 @Implementation(minSdk = P) nativeGetLocales(long ptr, boolean exclude_system)1301 protected static @Nullable String[] nativeGetLocales(long ptr, boolean exclude_system) { 1302 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1303 Set<String> locales = 1304 assetmanager.GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/); 1305 1306 String[] array = 1307 new String[locales.size()]; // env.NewObjectArray(locales.size(), g_stringClass, null); 1308 // if (array == null) { 1309 // return null; 1310 // } 1311 1312 int idx = 0; 1313 for (String locale : locales) { 1314 String java_string = locale; 1315 if (java_string == null) { 1316 return null; 1317 } 1318 // env.SetObjectArrayElement(array, idx++, java_string); 1319 array[idx++] = java_string; 1320 // env.DeleteLocalRef(java_string); 1321 } 1322 return array; 1323 } 1324 ConstructConfigurationObject( ResTable_config config)1325 static Configuration ConstructConfigurationObject(/* JNIEnv* env,*/ ResTable_config config) { 1326 // jobject result = 1327 // env.NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor); 1328 Configuration result = new Configuration(); 1329 // if (result == null) { 1330 // return null; 1331 // } 1332 1333 result.smallestScreenWidthDp = config.smallestScreenWidthDp; 1334 result.screenWidthDp = config.screenWidthDp; 1335 result.screenHeightDp = config.screenHeightDp; 1336 return result; 1337 } 1338 1339 // static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) { 1340 @Implementation(minSdk = P) nativeGetSizeConfigurations(long ptr)1341 protected static @Nullable Configuration[] nativeGetSizeConfigurations(long ptr) { 1342 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1343 Set<ResTable_config> configurations = 1344 assetmanager.GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/); 1345 1346 Configuration[] array = new Configuration[configurations.size()]; 1347 // env.NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, null); 1348 // if (array == null) { 1349 // return null; 1350 // } 1351 1352 int idx = 0; 1353 for (ResTable_config configuration : configurations) { 1354 Configuration java_configuration = ConstructConfigurationObject(configuration); 1355 // if (java_configuration == null) { 1356 // return null; 1357 // } 1358 1359 // env.SetObjectArrayElement(array, idx++, java_configuration); 1360 array[idx++] = java_configuration; 1361 // env.DeleteLocalRef(java_configuration); 1362 } 1363 return array; 1364 } 1365 1366 // static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, 1367 // jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr, 1368 // jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) 1369 // { 1370 @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)1371 protected static void nativeApplyStyle( 1372 long ptr, 1373 long theme_ptr, 1374 @AttrRes int def_style_attr, 1375 @StyleRes int def_style_resid, 1376 long xml_parser_ptr, 1377 @Nonnull int[] java_attrs, 1378 long out_values_ptr, 1379 long out_indices_ptr) { 1380 PerfStatsCollector.getInstance() 1381 .measure( 1382 "applyStyle", 1383 () -> 1384 nativeApplyStyle_measured( 1385 ptr, 1386 theme_ptr, 1387 def_style_attr, 1388 def_style_resid, 1389 xml_parser_ptr, 1390 java_attrs, 1391 out_values_ptr, 1392 out_indices_ptr)); 1393 } 1394 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)1395 private static void nativeApplyStyle_measured( 1396 long ptr, 1397 long theme_ptr, 1398 @AttrRes int def_style_attr, 1399 @StyleRes int def_style_resid, 1400 long xml_parser_ptr, 1401 @Nonnull int[] java_attrs, 1402 long out_values_ptr, 1403 long out_indices_ptr) { 1404 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1405 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1406 CHECK(theme.GetAssetManager() == assetmanager); 1407 // (void) assetmanager; 1408 1409 ResXMLParser xml_parser = 1410 xml_parser_ptr == 0 ? null : NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr); 1411 // int[] out_values = reinterpret_cast<int*>(out_values_ptr); 1412 // int[] out_indices = reinterpret_cast<int*>(out_indices_ptr); 1413 ShadowVMRuntime shadowVMRuntime = Shadow.extract(VMRuntime.getRuntime()); 1414 int[] out_values = (int[]) shadowVMRuntime.getObjectForAddress(out_values_ptr); 1415 int[] out_indices = (int[]) shadowVMRuntime.getObjectForAddress(out_indices_ptr); 1416 1417 int attrs_len = java_attrs.length; 1418 int[] attrs = 1419 java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null)); 1420 // if (attrs == null) { 1421 // return; 1422 // } 1423 1424 ApplyStyle( 1425 theme, 1426 xml_parser, 1427 (int) (def_style_attr), 1428 (int) (def_style_resid), 1429 attrs, 1430 attrs_len, 1431 out_values, 1432 out_indices); 1433 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1434 } 1435 1436 // static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, 1437 // jint def_style_attr, jint def_style_resid, jintArray 1438 // java_values, 1439 // jintArray java_attrs, jintArray out_java_values, 1440 // jintArray out_java_indices) { 1441 @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)1442 protected static boolean nativeResolveAttrs( 1443 long ptr, 1444 long theme_ptr, 1445 @AttrRes int def_style_attr, 1446 @StyleRes int def_style_resid, 1447 @Nullable int[] java_values, 1448 @Nonnull int[] java_attrs, 1449 @Nonnull int[] out_java_values, 1450 @Nonnull int[] out_java_indices) { 1451 int attrs_len = java_attrs.length; 1452 int out_values_len = out_java_values.length; 1453 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) { 1454 throw new IndexOutOfBoundsException("outValues too small"); 1455 } 1456 1457 int[] attrs = 1458 java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null)); 1459 if (attrs == null) { 1460 return JNI_FALSE; 1461 } 1462 1463 int[] values = null; 1464 int values_len = 0; 1465 if (java_values != null) { 1466 values_len = java_values.length; 1467 values = 1468 java_values; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_values, null)); 1469 if (values == null) { 1470 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1471 return JNI_FALSE; 1472 } 1473 } 1474 1475 int[] out_values = out_java_values; 1476 // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null)); 1477 if (out_values == null) { 1478 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1479 // if (values != null) { 1480 // env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT); 1481 // } 1482 return JNI_FALSE; 1483 } 1484 1485 int[] out_indices = null; 1486 if (out_java_indices != null) { 1487 int out_indices_len = out_java_indices.length; 1488 if (out_indices_len > attrs_len) { 1489 out_indices = out_java_indices; 1490 // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null)); 1491 if (out_indices == null) { 1492 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1493 // if (values != null) { 1494 // env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT); 1495 // } 1496 // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT); 1497 return JNI_FALSE; 1498 } 1499 } 1500 } 1501 1502 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1503 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1504 CHECK(theme.GetAssetManager() == assetmanager); 1505 // (void) assetmanager; 1506 1507 boolean result = 1508 ResolveAttrs( 1509 theme, 1510 (int) (def_style_attr), 1511 (int) (def_style_resid), 1512 values, 1513 values_len, 1514 attrs, 1515 attrs_len, 1516 out_values, 1517 out_indices); 1518 // if (out_indices != null) { 1519 // env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0); 1520 // } 1521 1522 // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0); 1523 // if (values != null) { 1524 // env.ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT); 1525 // } 1526 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1527 return result ? JNI_TRUE : JNI_FALSE; 1528 } 1529 1530 // static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, 1531 // jlong xml_parser_ptr, jintArray java_attrs, 1532 // jintArray out_java_values, jintArray out_java_indices) 1533 // { 1534 @Implementation(minSdk = P) nativeRetrieveAttributes( long ptr, long xml_parser_ptr, @Nonnull int[] java_attrs, @Nonnull int[] out_java_values, @Nonnull int[] out_java_indices)1535 protected static boolean nativeRetrieveAttributes( 1536 long ptr, 1537 long xml_parser_ptr, 1538 @Nonnull int[] java_attrs, 1539 @Nonnull int[] out_java_values, 1540 @Nonnull int[] out_java_indices) { 1541 int attrs_len = java_attrs.length; 1542 int out_values_len = out_java_values.length; 1543 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) { 1544 throw new IndexOutOfBoundsException("outValues too small"); 1545 } 1546 1547 int[] attrs = 1548 java_attrs; // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(java_attrs, null)); 1549 if (attrs == null) { 1550 return JNI_FALSE; 1551 } 1552 1553 int[] out_values = out_java_values; 1554 // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_values, null)); 1555 if (out_values == null) { 1556 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1557 return JNI_FALSE; 1558 } 1559 1560 int[] out_indices = null; 1561 if (out_java_indices != null) { 1562 int out_indices_len = out_java_indices.length; 1563 if (out_indices_len > attrs_len) { 1564 out_indices = out_java_indices; 1565 // reinterpret_cast<int*>(env.GetPrimitiveArrayCritical(out_java_indices, null)); 1566 if (out_indices == null) { 1567 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1568 // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT); 1569 return JNI_FALSE; 1570 } 1571 } 1572 } 1573 1574 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1575 ResXMLParser xml_parser = NATIVE_RES_XML_PARSERS.getNativeObject(xml_parser_ptr); 1576 1577 boolean result = 1578 RetrieveAttributes(assetmanager, xml_parser, attrs, attrs_len, out_values, out_indices); 1579 1580 // if (out_indices != null) { 1581 // env.ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0); 1582 // } 1583 // env.ReleasePrimitiveArrayCritical(out_java_values, out_values, 0); 1584 // env.ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); 1585 return result; 1586 } 1587 1588 // static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { 1589 @Implementation(minSdk = P) nativeThemeCreate(long ptr)1590 protected static long nativeThemeCreate(long ptr) { 1591 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1592 return Registries.NATIVE_THEME9_REGISTRY.register(assetmanager.NewTheme()); 1593 } 1594 1595 // static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) { 1596 @Implementation(minSdk = P, maxSdk = R) nativeThemeDestroy(long theme_ptr)1597 protected static void nativeThemeDestroy(long theme_ptr) { 1598 Registries.NATIVE_THEME9_REGISTRY.unregister(theme_ptr); 1599 } 1600 1601 @Implementation(minSdk = S) releaseTheme(long ptr)1602 protected void releaseTheme(long ptr) { 1603 Registries.NATIVE_THEME9_REGISTRY.unregister(ptr); 1604 reflector(AssetManagerReflector.class, realAssetManager).releaseTheme(ptr); 1605 } 1606 1607 // static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, 1608 // jint resid, jboolean force) { 1609 @Implementation(minSdk = P) nativeThemeApplyStyle( long ptr, long theme_ptr, @StyleRes int resid, boolean force)1610 protected static void nativeThemeApplyStyle( 1611 long ptr, long theme_ptr, @StyleRes int resid, boolean force) { 1612 // AssetManager is accessed via the theme, so grab an explicit lock here. 1613 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1614 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1615 CHECK(theme.GetAssetManager() == assetmanager); 1616 // (void) assetmanager; 1617 theme.ApplyStyle(resid, force); 1618 1619 // TODO(adamlesinski): Consider surfacing exception when result is failure. 1620 // CTS currently expects no exceptions from this method. 1621 // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid); 1622 // throw new IllegalArgumentException(error_msg.c_str()); 1623 } 1624 1625 // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr, 1626 // jlong src_theme_ptr) { 1627 @Implementation(minSdk = P, maxSdk = P) nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr)1628 protected static void nativeThemeCopy(long dst_theme_ptr, long src_theme_ptr) { 1629 Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr); 1630 Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr); 1631 if (!dst_theme.SetTo(src_theme)) { 1632 throw new IllegalArgumentException("Themes are from different AssetManagers"); 1633 } 1634 } 1635 1636 // static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr, 1637 // jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) { 1638 @Implementation(minSdk = Q) nativeThemeCopy( long dst_asset_manager_ptr, long dst_theme_ptr, long src_asset_manager_ptr, long src_theme_ptr)1639 protected static void nativeThemeCopy( 1640 long dst_asset_manager_ptr, 1641 long dst_theme_ptr, 1642 long src_asset_manager_ptr, 1643 long src_theme_ptr) { 1644 Theme dst_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(dst_theme_ptr); 1645 Theme src_theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(src_theme_ptr); 1646 if (dst_asset_manager_ptr != src_asset_manager_ptr) { 1647 CppAssetManager2 dst_assetmanager = AssetManagerFromLong(dst_asset_manager_ptr); 1648 CHECK(dst_theme.GetAssetManager() == dst_assetmanager); 1649 // (void) dst_assetmanager; 1650 1651 CppAssetManager2 src_assetmanager = AssetManagerFromLong(src_asset_manager_ptr); 1652 CHECK(src_theme.GetAssetManager() == src_assetmanager); 1653 // (void) src_assetmanager; 1654 1655 dst_theme.SetTo(src_theme); 1656 } else { 1657 dst_theme.SetTo(src_theme); 1658 } 1659 } 1660 1661 // static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) { 1662 @Implementation(minSdk = P, maxSdk = R) nativeThemeClear(long themePtr)1663 protected static void nativeThemeClear(long themePtr) { 1664 Registries.NATIVE_THEME9_REGISTRY.getNativeObject(themePtr).Clear(); 1665 } 1666 1667 // static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong 1668 // theme_ptr, 1669 // jint resid, jobject typed_value, 1670 // jboolean resolve_references) { 1671 @Implementation(minSdk = P) nativeThemeGetAttributeValue( long ptr, long theme_ptr, @AttrRes int resid, @Nonnull TypedValue typed_value, boolean resolve_references)1672 protected static int nativeThemeGetAttributeValue( 1673 long ptr, 1674 long theme_ptr, 1675 @AttrRes int resid, 1676 @Nonnull TypedValue typed_value, 1677 boolean resolve_references) { 1678 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1679 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1680 CHECK(theme.GetAssetManager() == assetmanager); 1681 // (void) assetmanager; // huh? 1682 1683 final Ref<Res_value> value = new Ref<>(null); 1684 final Ref<Integer> flags = new Ref<>(null); 1685 ApkAssetsCookie cookie = theme.GetAttribute(resid, value, flags); 1686 if (cookie.intValue() == kInvalidCookie) { 1687 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 1688 } 1689 1690 final Ref<Integer> ref = new Ref<>(0); 1691 if (resolve_references) { 1692 final Ref<ResTable_config> selected_config = new Ref<>(null); 1693 cookie = theme.GetAssetManager().ResolveReference(cookie, value, selected_config, flags, ref); 1694 if (cookie.intValue() == kInvalidCookie) { 1695 return ApkAssetsCookieToJavaCookie(K_INVALID_COOKIE); 1696 } 1697 } 1698 return CopyValue(cookie, value.get(), ref.get(), flags.get(), null, typed_value); 1699 } 1700 1701 // static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr, 1702 // jint priority, jstring tag, jstring prefix) { 1703 @Implementation(minSdk = P) nativeThemeDump( long ptr, long theme_ptr, int priority, String tag, String prefix)1704 protected static void nativeThemeDump( 1705 long ptr, long theme_ptr, int priority, String tag, String prefix) { 1706 CppAssetManager2 assetmanager = AssetManagerFromLong(ptr); 1707 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1708 CHECK(theme.GetAssetManager() == assetmanager); 1709 // (void) assetmanager; 1710 // (void) theme; 1711 // (void) priority; 1712 // (void) tag; 1713 // (void) prefix; 1714 } 1715 1716 // static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/, 1717 // jlong theme_ptr) { 1718 @Implementation(minSdk = P) nativeThemeGetChangingConfigurations(long theme_ptr)1719 protected static @NativeConfig int nativeThemeGetChangingConfigurations(long theme_ptr) { 1720 Theme theme = Registries.NATIVE_THEME9_REGISTRY.getNativeObject(theme_ptr); 1721 return (int) (theme.GetChangingConfigurations()); 1722 } 1723 1724 // static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) { 1725 @Implementation(minSdk = P) nativeAssetDestroy(long asset_ptr)1726 protected static void nativeAssetDestroy(long asset_ptr) { 1727 Registries.NATIVE_ASSET_REGISTRY.unregister(asset_ptr); 1728 } 1729 1730 // static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) { 1731 @Implementation(minSdk = P) nativeAssetReadChar(long asset_ptr)1732 protected static int nativeAssetReadChar(long asset_ptr) { 1733 Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr); 1734 byte[] b = new byte[1]; 1735 int res = asset.read(b, 1); 1736 return res == 1 ? (int) (b[0]) & 0xff : -1; 1737 } 1738 1739 // static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray 1740 // java_buffer, 1741 // jint offset, jint len) { 1742 @Implementation(minSdk = P) nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len)1743 protected static int nativeAssetRead(long asset_ptr, byte[] java_buffer, int offset, int len) 1744 throws IOException { 1745 if (len == 0) { 1746 return 0; 1747 } 1748 1749 int buffer_len = java_buffer.length; 1750 if (offset < 0 1751 || offset >= buffer_len 1752 || len < 0 1753 || len > buffer_len 1754 || offset > buffer_len - len) { 1755 throw new IndexOutOfBoundsException(); 1756 } 1757 1758 // ScopedByteArrayRW byte_array(env, java_buffer); 1759 // if (byte_array.get() == null) { 1760 // return -1; 1761 // } 1762 1763 Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr); 1764 // sint res = asset.read(byte_array.get() + offset, len); 1765 int res = asset.read(java_buffer, offset, len); 1766 if (res < 0) { 1767 throw new IOException(); 1768 } 1769 return res > 0 ? (int) (res) : -1; 1770 } 1771 1772 // static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset, 1773 // jint whence) { 1774 @Implementation(minSdk = P) nativeAssetSeek(long asset_ptr, long offset, int whence)1775 protected static long nativeAssetSeek(long asset_ptr, long offset, int whence) { 1776 Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr); 1777 return asset.seek((offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))); 1778 } 1779 1780 // static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) { 1781 @Implementation(minSdk = P) nativeAssetGetLength(long asset_ptr)1782 protected static long nativeAssetGetLength(long asset_ptr) { 1783 Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr); 1784 return asset.getLength(); 1785 } 1786 1787 // static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) 1788 // { 1789 @Implementation(minSdk = P) nativeAssetGetRemainingLength(long asset_ptr)1790 protected static long nativeAssetGetRemainingLength(long asset_ptr) { 1791 Asset asset = Registries.NATIVE_ASSET_REGISTRY.getNativeObject(asset_ptr); 1792 return asset.getRemainingLength(); 1793 } 1794 1795 // ---------------------------------------------------------------------------- 1796 1797 // JNI registration. 1798 // static JNINativeMethod gAssetManagerMethods[] = { 1799 // // AssetManager setup methods. 1800 // {"nativeCreate", "()J", (void*)NativeCreate}, 1801 // {"nativeDestroy", "(J)V", (void*)NativeDestroy}, 1802 // {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets}, 1803 // {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V", 1804 // (void*)NativeSetConfiguration}, 1805 // {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;", 1806 // (void*)NativeGetAssignedPackageIdentifiers}, 1807 // 1808 // // AssetManager file methods. 1809 // {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList}, 1810 // {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset}, 1811 // {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1812 // (void*)NativeOpenAssetFd}, 1813 // {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset}, 1814 // {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1815 // (void*)NativeOpenNonAssetFd}, 1816 // {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset}, 1817 // 1818 // // AssetManager resource methods. 1819 // {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", 1820 // (void*)NativeGetResourceValue}, 1821 // {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I", 1822 // (void*)NativeGetResourceBagValue}, 1823 // {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes}, 1824 // {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;", 1825 // (void*)NativeGetResourceStringArray}, 1826 // {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo}, 1827 // {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray}, 1828 // {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize}, 1829 // {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray}, 1830 // 1831 // // AssetManager resource name/ID methods. 1832 // {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", 1833 // (void*)NativeGetResourceIdentifier}, 1834 // {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName}, 1835 // {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", 1836 // (void*)NativeGetResourcePackageName}, 1837 // {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName}, 1838 // {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName}, 1839 // {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales}, 1840 // {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;", 1841 // (void*)NativeGetSizeConfigurations}, 1842 // 1843 // // Style attribute related methods. 1844 // {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle}, 1845 // {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs}, 1846 // {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes}, 1847 // 1848 // // Theme related methods. 1849 // {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate}, 1850 // {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy}, 1851 // {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle}, 1852 // {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy}, 1853 // {"nativeThemeClear", "(J)V", (void*)NativeThemeClear}, 1854 // {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I", 1855 // (void*)NativeThemeGetAttributeValue}, 1856 // {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump}, 1857 // {"nativeThemeGetChangingConfigurations", "(J)I", 1858 // (void*)NativeThemeGetChangingConfigurations}, 1859 // 1860 // // AssetInputStream methods. 1861 // {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy}, 1862 // {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar}, 1863 // {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead}, 1864 // {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek}, 1865 // {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength}, 1866 // {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength}, 1867 // 1868 // // System/idmap related methods. 1869 // {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, 1870 // 1871 // // Global management/debug methods. 1872 // {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, 1873 // {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations}, 1874 // {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount}, 1875 // }; 1876 // 1877 // int register_android_content_AssetManager(JNIEnv* env) { 1878 // jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets"); 1879 // gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J"); 1880 // 1881 // jclass typedValue = FindClassOrDie(env, "android/util/TypedValue"); 1882 // gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I"); 1883 // gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I"); 1884 // gTypedValueOffsets.mString = 1885 // GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;"); 1886 // gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I"); 1887 // gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I"); 1888 // gTypedValueOffsets.mChangingConfigurations = 1889 // GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I"); 1890 // gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I"); 1891 // 1892 // jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor"); 1893 // gAssetFileDescriptorOffsets.mFd = 1894 // GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;"); 1895 // gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", 1896 // "J"); 1897 // gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J"); 1898 // 1899 // jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager"); 1900 // gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J"); 1901 // 1902 // jclass stringClass = FindClassOrDie(env, "java/lang/String"); 1903 // g_stringClass = MakeGlobalRefOrDie(env, stringClass); 1904 // 1905 // jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray"); 1906 // gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass); 1907 // gSparseArrayOffsets.constructor = 1908 // GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V"); 1909 // gSparseArrayOffsets.put = 1910 // GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V"); 1911 // 1912 // jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration"); 1913 // gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass); 1914 // gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", 1915 // "()V"); 1916 // gConfigurationOffsets.mSmallestScreenWidthDpOffset = 1917 // GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I"); 1918 // gConfigurationOffsets.mScreenWidthDpOffset = 1919 // GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I"); 1920 // gConfigurationOffsets.mScreenHeightDpOffset = 1921 // GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I"); 1922 // 1923 // return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods, 1924 // NELEM(gAssetManagerMethods)); 1925 // } 1926 1927 @ForType(AssetManager.class) 1928 interface AssetManagerReflector { 1929 1930 @Static 1931 @Direct createSystemAssetsInZygoteLocked()1932 void createSystemAssetsInZygoteLocked(); 1933 1934 @Direct releaseTheme(long ptr)1935 void releaseTheme(long ptr); 1936 } 1937 } 1938 // namespace android 1939