• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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