1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.layoutlib.create; 18 19 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 20 import com.android.tools.layoutlib.java.LinkedHashMap_Delegate; 21 import com.android.tools.layoutlib.java.NioUtils_Delegate; 22 import com.android.tools.layoutlib.java.Reference_Delegate; 23 24 import org.objectweb.asm.Opcodes; 25 import org.objectweb.asm.Type; 26 27 import java.lang.ref.Reference; 28 import java.lang.ref.WeakReference; 29 import java.util.Arrays; 30 import java.util.HashSet; 31 import java.util.LinkedHashMap; 32 import java.util.Locale; 33 import java.util.Map; 34 import java.util.Set; 35 36 /** 37 * Describes the work to be done by {@link AsmGenerator}. 38 */ 39 public final class CreateInfo implements ICreateInfo { 40 41 @Override getMethodReplacers()42 public MethodReplacer[] getMethodReplacers() { 43 return METHOD_REPLACERS; 44 } 45 46 @Override getInjectedClasses()47 public Class<?>[] getInjectedClasses() { 48 return INJECTED_CLASSES; 49 } 50 51 @Override getDelegateMethods()52 public String[] getDelegateMethods() { 53 return DELEGATE_METHODS; 54 } 55 56 @Override getDelegateClassNatives()57 public String[] getDelegateClassNatives() { 58 return DELEGATE_CLASS_NATIVES; 59 } 60 61 @Override getDelegateClassNativesToNatives()62 public String[] getDelegateClassNativesToNatives() { 63 return DELEGATE_CLASS_NATIVES_TO_NATIVES; 64 } 65 66 @Override shouldKeepAllNativeClasses()67 public boolean shouldKeepAllNativeClasses() { 68 return false; 69 } 70 71 @Override getKeepClassNatives()72 public String[] getKeepClassNatives() { 73 return KEEP_CLASS_NATIVES; 74 } 75 76 @Override getRenamedClasses()77 public String[] getRenamedClasses() { 78 return RENAMED_CLASSES; 79 } 80 81 @Override getDeleteReturns()82 public String[] getDeleteReturns() { 83 return DELETE_RETURNS; 84 } 85 86 @Override getJavaPkgClasses()87 public String[] getJavaPkgClasses() { 88 return JAVA_PKG_CLASSES; 89 } 90 91 @Override getRefactoredClasses()92 public String[] getRefactoredClasses() { 93 return REFACTOR_CLASSES; 94 } 95 96 @Override getExcludedClasses()97 public String[] getExcludedClasses() { 98 String[] refactoredClasses = getJavaPkgClasses(); 99 int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length; 100 Set<String> excludedClasses = new HashSet<>(count); 101 for (int i = 0; i < refactoredClasses.length; i+=2) { 102 excludedClasses.add(refactoredClasses[i]); 103 } 104 excludedClasses.addAll(Arrays.asList(EXCLUDED_CLASSES)); 105 return excludedClasses.toArray(new String[0]); 106 } 107 108 @Override getPromotedFields()109 public String[] getPromotedFields() { 110 return PROMOTED_FIELDS; 111 } 112 113 @Override getPromotedMethods()114 public String[] getPromotedMethods() { 115 return PROMOTED_METHODS; 116 } 117 118 @Override getPromotedClasses()119 public String[] getPromotedClasses() { 120 return PROMOTED_CLASSES; 121 } 122 123 @Override getInjectedMethodsMap()124 public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { 125 return INJECTED_METHODS; 126 } 127 128 @Override getDeferredStaticInitializerClasses()129 public String[] getDeferredStaticInitializerClasses() { 130 return DEFERRED_STATIC_INITIALIZER_CLASSES; 131 } 132 133 @Override getRemovedFinalModifierFields()134 public String[] getRemovedFinalModifierFields() { 135 return REMOVED_FINAL_MODIFIER_FIELDS; 136 } 137 138 //----- 139 140 private static final MethodReplacer[] METHOD_REPLACERS = new MethodReplacer[] { 141 new SystemLoadLibraryReplacer(), 142 new SystemArrayCopyReplacer(), 143 new LocaleGetDefaultReplacer(), 144 new SystemLogReplacer(), 145 new SystemNanoTimeReplacer(), 146 new SystemCurrentTimeMillisReplacer(), 147 new LinkedHashMapEldestReplacer(), 148 new ContextGetClassLoaderReplacer(), 149 new NativeInitPathReplacer(), 150 new AdaptiveIconMaskReplacer(), 151 new ActivityThreadInAnimationReplacer(), 152 new ReferenceRefersToReplacer(), 153 new HtmlApplicationResourceReplacer(), 154 new NativeAllocationRegistryApplyFreeFunctionReplacer(), 155 new LineBreakConfigApplicationInfoReplacer(), 156 new NioUtilsFreeBufferReplacer(), 157 }; 158 159 /** 160 * The list of class from layoutlib_create to inject in layoutlib. 161 */ 162 private final static Class<?>[] INJECTED_CLASSES = new Class<?>[] { 163 OverrideMethod.class, 164 MethodListener.class, 165 MethodAdapter.class, 166 ICreateInfo.class, 167 CreateInfo.class, 168 LayoutlibDelegate.class, 169 InjectMethodRunnable.class, 170 InjectMethodRunnables.class, 171 /* Java package classes */ 172 LinkedHashMap_Delegate.class, 173 NioUtils_Delegate.class, 174 Reference_Delegate.class, 175 }; 176 177 /** 178 * The list of methods to rewrite as delegates. 179 */ 180 private final static String[] DELEGATE_METHODS = NativeConfig.DELEGATE_METHODS; 181 182 /** 183 * The list of classes on which to delegate all native methods. 184 */ 185 private final static String[] DELEGATE_CLASS_NATIVES = NativeConfig.DELEGATE_CLASS_NATIVES; 186 187 private final static String[] DELEGATE_CLASS_NATIVES_TO_NATIVES = new String[] {}; 188 189 /** 190 * The list of classes on which NOT to delegate any native method. 191 */ 192 private final static String[] KEEP_CLASS_NATIVES = new String[] { 193 "android.animation.PropertyValuesHolder", 194 "android.content.res.StringBlock", 195 "android.content.res.XmlBlock", 196 "android.graphics.BaseCanvas", 197 "android.graphics.BaseRecordingCanvas", 198 "android.graphics.Bitmap", 199 "android.graphics.BitmapRegionDecoder", 200 "android.graphics.BitmapFactory", 201 "android.graphics.BitmapShader", 202 "android.graphics.BlendModeColorFilter", 203 "android.graphics.BlurMaskFilter", 204 "android.graphics.BlurShader", 205 "android.graphics.Camera", 206 "android.graphics.Canvas", 207 "android.graphics.CanvasProperty", 208 "android.graphics.Color", 209 "android.graphics.ColorFilter", 210 "android.graphics.ColorMatrixColorFilter", 211 "android.graphics.ColorSpace$Rgb$Native", 212 "android.graphics.ComposePathEffect", 213 "android.graphics.ComposeShader", 214 "android.graphics.CornerPathEffect", 215 "android.graphics.DashPathEffect", 216 "android.graphics.DiscretePathEffect", 217 "android.graphics.DrawFilter", 218 "android.graphics.EmbossMaskFilter", 219 "android.graphics.FontFamily", 220 "android.graphics.Gainmap", 221 "android.graphics.HardwareBufferRenderer", 222 "android.graphics.HardwareRenderer", 223 "android.graphics.HardwareRendererObserver", 224 "android.graphics.ImageDecoder", 225 "android.graphics.Interpolator", 226 "android.graphics.LightingColorFilter", 227 "android.graphics.LinearGradient", 228 "android.graphics.MaskFilter", 229 "android.graphics.Matrix", 230 "android.graphics.Matrix$ExtraNatives", 231 "android.graphics.Mesh", 232 "android.graphics.MeshSpecification", 233 "android.graphics.NinePatch", 234 "android.graphics.Paint", 235 "android.graphics.PaintFlagsDrawFilter", 236 "android.graphics.Path", 237 "android.graphics.PathDashPathEffect", 238 "android.graphics.PathEffect", 239 "android.graphics.PathIterator", 240 "android.graphics.PathMeasure", 241 "android.graphics.Picture", 242 "android.graphics.PorterDuffColorFilter", 243 "android.graphics.RadialGradient", 244 "android.graphics.RecordingCanvas", 245 "android.graphics.Region", 246 "android.graphics.RegionIterator", 247 "android.graphics.RenderEffect", 248 "android.graphics.RenderNode", 249 "android.graphics.RuntimeColorFilter", 250 "android.graphics.RuntimeShader", 251 "android.graphics.Shader", 252 "android.graphics.SumPathEffect", 253 "android.graphics.SweepGradient", 254 "android.graphics.TableMaskFilter", 255 "android.graphics.Typeface", 256 "android.graphics.YuvImage", 257 "android.graphics.animation.NativeInterpolatorFactory", 258 "android.graphics.animation.RenderNodeAnimator", 259 "android.graphics.drawable.AnimatedImageDrawable", 260 "android.graphics.drawable.AnimatedVectorDrawable", 261 "android.graphics.drawable.VectorDrawable", 262 "android.graphics.fonts.Font", 263 "android.graphics.fonts.Font$Builder", 264 "android.graphics.fonts.FontFamily", 265 "android.graphics.fonts.FontFamily$Builder", 266 "android.graphics.fonts.FontFileUtil", 267 "android.graphics.fonts.SystemFonts", 268 "android.graphics.text.PositionedGlyphs", 269 "android.graphics.text.GraphemeBreak", 270 "android.graphics.text.LineBreaker", 271 "android.graphics.text.MeasuredText", 272 "android.graphics.text.MeasuredText$Builder", 273 "android.graphics.text.TextRunShaper", 274 "android.media.ImageReader", 275 "android.media.ImageReader$SurfaceImage", 276 "android.media.PublicFormatUtils", 277 "android.os.SystemProperties", 278 "android.text.AndroidCharacter", 279 "android.text.Hyphenator", 280 "android.util.EventLog", 281 "android.util.Log", 282 "android.util.PathParser", 283 "android.view.MotionEvent", 284 "android.view.Surface", 285 "android.view.VelocityTracker", 286 "com.android.internal.util.VirtualRefBasePtr", 287 "libcore.util.NativeAllocationRegistry", 288 }; 289 290 /** 291 * The list of classes to rename, must be an even list: the binary FQCN 292 * of class to replace followed by the new FQCN. 293 */ 294 private final static String[] RENAMED_CLASSES = 295 new String[] { 296 "android.os.ServiceManager", "android.os._Original_ServiceManager", 297 "android.view.textservice.TextServicesManager", "android.view.textservice._Original_TextServicesManager", 298 "android.view.SurfaceView", "android.view._Original_SurfaceView", 299 "android.view.WindowManagerImpl", "android.view._Original_WindowManagerImpl", 300 "android.webkit.WebView", "android.webkit._Original_WebView", 301 }; 302 303 /** 304 * The list of class references to update, must be an even list: the binary 305 * FQCN of class to replace followed by the new FQCN. The classes to 306 * replace are to be excluded from the output. 307 */ 308 private final static String[] JAVA_PKG_CLASSES = 309 new String[] { 310 "sun.misc.Cleaner", "com.android.layoutlib.bridge.libcore.util.Cleaner", 311 }; 312 313 /** 314 * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and 315 * {@link #getJavaPkgClasses()}. 316 * Classes included here will be renamed and then all their references in any other classes 317 * will be also modified. 318 * FQCN of class to refactor followed by its new FQCN. 319 */ 320 private final static String[] REFACTOR_CLASSES = 321 new String[] { 322 "android.os.Build", "android.os._Original_Build", 323 }; 324 325 private final static String[] EXCLUDED_CLASSES = 326 new String[] { 327 "android.preference.PreferenceActivity", 328 "java.**", 329 "kotlin.**", 330 "org.kxml2.io.KXmlParser", 331 "org.xmlpull.**", 332 "sun.**", 333 }; 334 335 /** 336 * List of fields for which we will update the visibility to be public. This is sometimes 337 * needed when access from the delegate classes is needed. 338 */ 339 private final static String[] PROMOTED_FIELDS = new String[] { 340 "android.animation.AnimationHandler#mDelayedCallbackStartTime", 341 "android.animation.AnimationHandler#mAnimationCallbacks", 342 "android.animation.AnimationHandler#mCommitCallbacks", 343 "android.animation.AnimatorSet#mLastFrameTime", 344 "android.animation.PropertyValuesHolder#sSetterPropertyMap", 345 "android.animation.PropertyValuesHolder#sGetterPropertyMap", 346 "android.animation.PropertyValuesHolder$IntPropertyValuesHolder#sJNISetterPropertyMap", 347 "android.animation.PropertyValuesHolder$FloatPropertyValuesHolder#sJNISetterPropertyMap", 348 "android.animation.PropertyValuesHolder$MultiFloatValuesHolder#sJNISetterPropertyMap", 349 "android.animation.PropertyValuesHolder$MultiIntValuesHolder#sJNISetterPropertyMap", 350 "android.graphics.Bitmap#sAllBitmaps", 351 "android.graphics.ImageDecoder$InputStreamSource#mInputStream", 352 "android.graphics.Typeface#DEFAULT_FAMILY", 353 "android.graphics.Typeface#sDynamicTypefaceCache", 354 "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI#mSet", 355 "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#mPendingAnimationActions", 356 "android.graphics.drawable.AnimatedVectorDrawable#mAnimatorSet", 357 "android.graphics.drawable.DrawableInflater#mRes", 358 "android.hardware.input.InputManagerGlobal#sInstance", 359 "android.util.Pools$SimplePool#mPool", 360 "android.util.Pools$SimplePool#mPoolSize", 361 "android.view.Choreographer#mCallbackQueues", // required for tests only 362 "android.view.Choreographer#mCallbacksRunning", 363 "android.view.Choreographer#mFrameScheduled", 364 "android.view.Choreographer$CallbackQueue#mHead", // required for tests only 365 "android.view.View#sAlwaysRemeasureExactly", 366 "android.view.ViewRootImpl#mTmpFrames", 367 "android.view.accessibility.AccessibilityInteractionClient#sCaches", 368 "android.view.accessibility.AccessibilityInteractionClient#sClients", 369 "android.view.accessibility.AccessibilityInteractionClient#sConnectionCache", 370 "android.view.accessibility.AccessibilityInteractionClient#sDirectConnectionCount", 371 "android.view.accessibility.AccessibilityInteractionClient#sScrollingWindows", 372 "com.android.internal.util.ArrayUtils#sCache", 373 }; 374 375 /** 376 * List of methods for which we will update the visibility to be public. 377 */ 378 private final static String[] PROMOTED_METHODS = new String[] { 379 "android.animation.AnimationHandler#doAnimationFrame", 380 "android.content.res.StringBlock#addParagraphSpan", 381 "android.content.res.StringBlock#getColor", 382 "android.graphics.Bitmap#setNinePatchChunk", 383 "android.graphics.Path#nInit", 384 "android.graphics.Typeface$Builder#createAssetUid", 385 "android.hardware.input.InputManagerGlobal#<init>", 386 "android.view.ViewRootImpl#getRootMeasureSpec", 387 }; 388 389 /** 390 * List of classes to be promoted to public visibility. Prefer using PROMOTED_FIELDS to this 391 * if possible. 392 */ 393 private final static String[] PROMOTED_CLASSES = new String[] { 394 "android.content.res.StringBlock$Height", 395 "android.graphics.ImageDecoder$InputStreamSource", 396 "android.graphics.ImageDecoder$ResourceSource", 397 "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI", 398 "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator", 399 "android.os.PerfettoTrackEventExtra$CounterInt64", 400 "android.os.PerfettoTrackEventExtra$CounterDouble", 401 "android.os.PerfettoTrackEventExtra$Flow", 402 "android.os.PerfettoTrackEventExtra$Proto", 403 "android.view.Choreographer$CallbackQueue", // required for tests only 404 }; 405 406 /** 407 * List of classes for which the methods returning them should be deleted. 408 * The array contains a list of null terminated section starting with the name of the class 409 * to rename in which the methods are deleted, followed by a list of return types identifying 410 * the methods to delete. 411 */ 412 private final static String[] DELETE_RETURNS = 413 new String[] { 414 null }; // separator, for next class/methods list. 415 416 private final static String[] DEFERRED_STATIC_INITIALIZER_CLASSES = 417 NativeConfig.DEFERRED_STATIC_INITIALIZER_CLASSES; 418 419 private final static Map<String, InjectMethodRunnable> INJECTED_METHODS = Map.of( 420 "android.content.Context", InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER); 421 422 /** 423 * List of fields for which we will remove the final modifier. 424 */ 425 private final static String[] REMOVED_FINAL_MODIFIER_FIELDS = 426 new String[]{"android.animation.AnimationHandler#sAnimatorHandler"}; 427 428 public static class LinkedHashMapEldestReplacer implements MethodReplacer { 429 430 private final String VOID_TO_MAP_ENTRY = 431 Type.getMethodDescriptor(Type.getType(Map.Entry.class)); 432 private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class); 433 434 @Override isNeeded(String owner, String name, String desc, String sourceClass)435 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 436 return LINKED_HASH_MAP.equals(owner) && 437 "eldest".equals(name) && 438 VOID_TO_MAP_ENTRY.equals(desc); 439 } 440 441 @Override replace(MethodInformation mi)442 public void replace(MethodInformation mi) { 443 mi.opcode = Opcodes.INVOKESTATIC; 444 mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class); 445 mi.desc = Type.getMethodDescriptor( 446 Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class)); 447 } 448 } 449 450 private static class ContextGetClassLoaderReplacer implements MethodReplacer { 451 // When LayoutInflater asks for a class loader, we must return the class loader that 452 // cannot return app's custom views/classes. This is so that in case of any failure 453 // or exception when instantiating the views, the IDE can replace it with a mock view 454 // and have proper error handling. However, if a custom view asks for the class 455 // loader, we must return a class loader that can find app's custom views as well. 456 // Thus, we rewrite the call to get class loader in LayoutInflater to 457 // getFrameworkClassLoader and inject a new method in Context. This leaves the normal 458 // method: Context.getClassLoader() free to be used by the apps. 459 private final String VOID_TO_CLASS_LOADER = 460 Type.getMethodDescriptor(Type.getType(ClassLoader.class)); 461 462 @Override isNeeded(String owner, String name, String desc, String sourceClass)463 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 464 return owner.equals("android/content/Context") && 465 sourceClass.equals("android/view/LayoutInflater") && 466 name.equals("getClassLoader") && 467 desc.equals(VOID_TO_CLASS_LOADER); 468 } 469 470 @Override replace(MethodInformation mi)471 public void replace(MethodInformation mi) { 472 mi.name = "getFrameworkClassLoader"; 473 } 474 } 475 476 private static class SystemCurrentTimeMillisReplacer implements MethodReplacer { 477 @Override isNeeded(String owner, String name, String desc, String sourceClass)478 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 479 return Type.getInternalName(System.class).equals(owner) && name.equals("currentTimeMillis"); 480 } 481 482 @Override replace(MethodInformation mi)483 public void replace(MethodInformation mi) { 484 mi.name = "currentTimeMillis"; 485 mi.owner = "com/android/internal/lang/System_Delegate"; 486 } 487 } 488 489 private static class SystemNanoTimeReplacer implements MethodReplacer { 490 @Override isNeeded(String owner, String name, String desc, String sourceClass)491 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 492 return Type.getInternalName(System.class).equals(owner) && name.equals("nanoTime"); 493 } 494 495 @Override replace(MethodInformation mi)496 public void replace(MethodInformation mi) { 497 mi.name = "nanoTime"; 498 mi.owner = "com/android/internal/lang/System_Delegate"; 499 } 500 } 501 502 public static class SystemLogReplacer implements MethodReplacer { 503 @Override isNeeded(String owner, String name, String desc, String sourceClass)504 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 505 return Type.getInternalName(System.class).equals(owner) && name.length() == 4 506 && name.startsWith("log"); 507 } 508 509 @Override replace(MethodInformation mi)510 public void replace(MethodInformation mi) { 511 assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V") 512 || mi.desc.equals("(Ljava/lang/String;)V"); 513 mi.name = "log"; 514 mi.owner = "com/android/internal/lang/System_Delegate"; 515 } 516 } 517 518 /** 519 * Platform code should not loadLibrary on its own. Layoutlib loading infrastructure takes case 520 * of loading all the necessary native libraries (having the right paths etc.) 521 */ 522 public static class SystemLoadLibraryReplacer implements MethodReplacer { 523 @Override isNeeded(String owner, String name, String desc, String sourceClass)524 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 525 return Type.getInternalName(System.class).equals(owner) && name.equals("loadLibrary"); 526 } 527 528 @Override replace(MethodInformation mi)529 public void replace(MethodInformation mi) { 530 mi.owner = "com/android/internal/lang/System_Delegate"; 531 } 532 } 533 534 private static class LocaleGetDefaultReplacer implements MethodReplacer { 535 536 @Override isNeeded(String owner, String name, String desc, String sourceClass)537 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 538 return Type.getInternalName(Locale.class).equals(owner) 539 && "getDefault".equals(name) 540 && desc.equals(Type.getMethodDescriptor(Type.getType(Locale.class))); 541 } 542 543 @Override replace(MethodInformation mi)544 public void replace(MethodInformation mi) { 545 mi.owner = "com/android/layoutlib/bridge/android/AndroidLocale"; 546 } 547 } 548 549 private static class SystemArrayCopyReplacer implements MethodReplacer { 550 /** 551 * Descriptors for specialized versions {@link System#arraycopy} that are not present on the 552 * Desktop VM. 553 */ 554 private static final Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList( 555 "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V", 556 "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V")); 557 558 @Override isNeeded(String owner, String name, String desc, String sourceClass)559 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 560 return Type.getInternalName(System.class).equals(owner) && "arraycopy".equals(name) && 561 ARRAYCOPY_DESCRIPTORS.contains(desc); 562 } 563 564 @Override replace(MethodInformation mi)565 public void replace(MethodInformation mi) { 566 mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V"; 567 } 568 } 569 570 public static class NativeInitPathReplacer implements MethodReplacer { 571 @Override isNeeded(String owner, String name, String desc, String sourceClass)572 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 573 return "android/graphics/Path".equals(owner) && 574 "nInit".equals(name) && "(J)J".equals(desc); 575 } 576 577 @Override replace(MethodInformation mi)578 public void replace(MethodInformation mi) { 579 mi.owner = "android/graphics/Path_Delegate"; 580 mi.opcode = Opcodes.INVOKESTATIC; 581 } 582 } 583 584 public static class AdaptiveIconMaskReplacer implements MethodReplacer { 585 @Override isNeeded(String owner, String name, String desc, String sourceClass)586 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 587 return "android/graphics/drawable/AdaptiveIconDrawable".equals(sourceClass) && 588 "android/content/res/Resources".equals(owner) && 589 name.equals("getString"); 590 } 591 592 @Override replace(MethodInformation mi)593 public void replace(MethodInformation mi) { 594 mi.owner = "android/graphics/drawable/AdaptiveIconDrawable_Delegate"; 595 mi.name = "getResourceString"; 596 mi.opcode = Opcodes.INVOKESTATIC; 597 mi.desc = "(Landroid/content/res/Resources;I)Ljava/lang/String;"; 598 } 599 } 600 601 public static class ActivityThreadInAnimationReplacer implements MethodReplacer { 602 @Override isNeeded(String owner, String name, String desc, String sourceClass)603 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 604 return ("android/app/ActivityThread").equals(owner) && 605 name.equals("getSystemUiContext") && 606 sourceClass.equals("android/view/animation/Animation"); 607 } 608 609 @Override replace(MethodInformation mi)610 public void replace(MethodInformation mi) { 611 mi.owner = "android/app/ActivityThread_Delegate"; 612 mi.opcode = Opcodes.INVOKESTATIC; 613 mi.desc = "()Landroid/content/Context;"; 614 } 615 } 616 617 public static class ReferenceRefersToReplacer implements MethodReplacer { 618 @Override isNeeded(String owner, String name, String desc, String sourceClass)619 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 620 return Type.getInternalName(WeakReference.class).equals(owner) && 621 "refersTo".equals(name); 622 } 623 624 @Override replace(MethodInformation mi)625 public void replace(MethodInformation mi) { 626 mi.opcode = Opcodes.INVOKESTATIC; 627 mi.owner = Type.getInternalName(Reference_Delegate.class); 628 mi.desc = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(Reference.class), 629 Type.getType(Object.class)); 630 } 631 } 632 633 public static class HtmlApplicationResourceReplacer implements MethodReplacer { 634 @Override isNeeded(String owner, String name, String desc, String sourceClass)635 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 636 return ("android/text/Html".equals(sourceClass) || 637 "android/text/HtmlToSpannedConverter".equals(sourceClass)) && 638 "android/app/Application".equals(owner) && 639 name.equals("getResources"); 640 } 641 642 @Override replace(MethodInformation mi)643 public void replace(MethodInformation mi) { 644 mi.owner = "android/app/Application_Delegate"; 645 mi.name = "getResources"; 646 mi.opcode = Opcodes.INVOKESTATIC; 647 mi.desc = "(Landroid/app/Application;)Landroid/content/res/Resources;"; 648 } 649 } 650 651 public static class NativeAllocationRegistryApplyFreeFunctionReplacer 652 implements MethodReplacer { 653 @Override isNeeded(String owner, String name, String desc, String sourceClass)654 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 655 return "libcore/util/NativeAllocationRegistry".equals(owner) && 656 "applyFreeFunction".equals(name) && "(JJ)V".equals(desc); 657 } 658 659 @Override replace(MethodInformation mi)660 public void replace(MethodInformation mi) { 661 mi.owner = "libcore/util/NativeAllocationRegistry_Delegate"; 662 mi.opcode = Opcodes.INVOKESTATIC; 663 } 664 } 665 666 public static class LineBreakConfigApplicationInfoReplacer implements MethodReplacer { 667 @Override isNeeded(String owner, String name, String desc, String sourceClass)668 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 669 return "android/graphics/text/LineBreakConfig".equals(sourceClass) && 670 "android/app/Application".equals(owner) && 671 name.equals("getApplicationInfo"); 672 } 673 674 @Override replace(MethodInformation mi)675 public void replace(MethodInformation mi) { 676 mi.owner = "android/app/Application_Delegate"; 677 mi.name = "getApplicationInfo"; 678 mi.opcode = Opcodes.INVOKESTATIC; 679 mi.desc = "(Landroid/app/Application;)Landroid/content/pm/ApplicationInfo;"; 680 } 681 } 682 683 public static class NioUtilsFreeBufferReplacer implements MethodReplacer { 684 @Override isNeeded(String owner, String name, String desc, String sourceClass)685 public boolean isNeeded(String owner, String name, String desc, String sourceClass) { 686 return "java/nio/NioUtils".equals(owner) && name.equals("freeDirectBuffer"); 687 } 688 689 @Override replace(MethodInformation mi)690 public void replace(MethodInformation mi) { 691 mi.owner = Type.getInternalName(NioUtils_Delegate.class); 692 } 693 } 694 } 695