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