1010import java .util .Map ;
1111import java .util .Set ;
1212
13+ import heros .solver .Pair ;
1314import soot .MethodOrMethodContext ;
1415import soot .PackManager ;
16+ import soot .RefType ;
1517import soot .Scene ;
1618import soot .SceneTransformer ;
1719import soot .SootClass ;
@@ -48,22 +50,28 @@ public class DefaultCallbackAnalyzer extends AbstractCallbackAnalyzer implements
4850 private AndroidEntryPointUtils entryPointUtils = new AndroidEntryPointUtils ();
4951 private Set <IMemoryBoundedSolverStatusNotification > notificationListeners = new HashSet <>();
5052 private ISolverTerminationReason isKilled = null ;
53+ private MultiMap <SootClass , AndroidCallbackDefinition > viewCallbacks ;
5154
5255 public DefaultCallbackAnalyzer (InfoflowAndroidConfiguration config , Set <SootClass > entryPointClasses )
5356 throws IOException {
5457 super (config , entryPointClasses );
5558 }
5659
5760 public DefaultCallbackAnalyzer (InfoflowAndroidConfiguration config , Set <SootClass > entryPointClasses ,
58- String callbackFile ) throws IOException {
61+ MultiMap < SootClass , AndroidCallbackDefinition > viewCallbacks , String callbackFile ) throws IOException {
5962 super (config , entryPointClasses , callbackFile );
63+ this .viewCallbacks = viewCallbacks ;
6064 }
6165
6266 public DefaultCallbackAnalyzer (InfoflowAndroidConfiguration config , Set <SootClass > entryPointClasses ,
63- Set <String > androidCallbacks ) throws IOException {
67+ MultiMap <SootClass , AndroidCallbackDefinition > viewCallbacks , Set <String > androidCallbacks )
68+ throws IOException {
6469 super (config , entryPointClasses , androidCallbacks );
70+ this .viewCallbacks = viewCallbacks ;
6571 }
6672
73+ QueueReader <MethodOrMethodContext > reachableChangedListener ;
74+
6775 /**
6876 * Collects the callback methods for all Android default handlers implemented in
6977 * the source code. Note that this operation runs inside Soot, so this method
@@ -100,17 +108,31 @@ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes")
100108 getLifecycleMethods (sc ));
101109
102110 // Check for callbacks registered in the code
103- analyzeRechableMethods (sc , methods );
111+ analyzeReachableMethods (sc , methods );
104112
105113 // Check for method overrides
106114 analyzeMethodOverrideCallbacks (sc );
107115 analyzeClassInterfaceCallbacks (sc , sc , sc );
108116 }
117+ reachableChangedListener = Scene .v ().getReachableMethods ().listener ();
109118 logger .info ("Callback analysis done." );
110119 } else {
111120 // Incremental mode, only process the worklist
112121 logger .info (String .format ("Running incremental callback analysis for %d components..." ,
113122 callbackWorklist .size ()));
123+ // Find the mappings between classes and layouts
124+ findClassLayoutMappings ();
125+
126+ MultiMap <SootMethod , SootClass > reverseViewCallbacks = new HashMultiMap <>();
127+ for (Pair <SootClass , AndroidCallbackDefinition > i : viewCallbacks )
128+ reverseViewCallbacks .put (i .getO2 ().getTargetMethod (), i .getO1 ());
129+ while (reachableChangedListener .hasNext ()) {
130+ SootMethod m = reachableChangedListener .next ().method ();
131+ Set <SootClass > o = reverseViewCallbacks .get (m );
132+ for (SootClass i : o ) {
133+ callbackWorklist .put (i , m );
134+ }
135+ }
114136
115137 MultiMap <SootClass , SootMethod > workList = new HashMultiMap <>(callbackWorklist );
116138 for (Iterator <SootClass > it = workList .keySet ().iterator (); it .hasNext ();) {
@@ -122,6 +144,10 @@ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes")
122144 Set <SootMethod > callbacks = callbackWorklist .get (componentClass );
123145 callbackWorklist .remove (componentClass );
124146
147+ Set <SootClass > activityComponents = fragmentClassesRev .get (componentClass );
148+ if (activityComponents == null || activityComponents .isEmpty ())
149+ activityComponents = Collections .singleton (componentClass );
150+
125151 // Check whether we're already beyond the maximum number
126152 // of callbacks for the current component
127153 if (config .getCallbackConfig ().getMaxCallbacksPerComponent () > 0
@@ -133,15 +159,21 @@ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes")
133159
134160 // Check for method overrides. The whole class might be new.
135161 analyzeMethodOverrideCallbacks (componentClass );
136- analyzeClassInterfaceCallbacks (componentClass , componentClass , componentClass );
162+ for (SootClass activityComponent : activityComponents ) {
163+ if (activityComponent == null )
164+ activityComponent = componentClass ;
165+ analyzeClassInterfaceCallbacks (componentClass , componentClass , activityComponent );
166+ }
137167
138168 // Collect all methods that we need to analyze
139169 List <MethodOrMethodContext > entryClasses = new ArrayList <>(callbacks .size ());
140- for (SootMethod sm : callbacks )
141- entryClasses .add (sm );
170+ for (SootMethod sm : callbacks ) {
171+ if (sm != null )
172+ entryClasses .add (sm );
173+ }
142174
143175 // Check for further callback declarations
144- analyzeRechableMethods (componentClass , entryClasses );
176+ analyzeReachableMethods (componentClass , entryClasses );
145177 }
146178 logger .info ("Incremental callback analysis done." );
147179 }
@@ -226,7 +258,7 @@ private static Collection<? extends MethodOrMethodContext> getLifecycleMethods(S
226258 return lifecycleMethods ;
227259 }
228260
229- private void analyzeRechableMethods (SootClass lifecycleElement , List <MethodOrMethodContext > methods ) {
261+ private void analyzeReachableMethods (SootClass lifecycleElement , List <MethodOrMethodContext > methods ) {
230262 // Make sure to exclude all other edges in the callgraph except for the
231263 // edges start in the lifecycle methods we explicitly pass in
232264 ComponentReachableMethods rm = new ComponentReachableMethods (config , lifecycleElement , methods );
@@ -279,40 +311,53 @@ protected void checkAndAddFragment(SootClass componentClass, SootClass fragmentC
279311 }
280312 }
281313
314+ Iterator <MethodOrMethodContext > rmIterator ;
315+
282316 /**
283317 * Finds the mappings between classes and their respective layout files
284318 */
285319 private void findClassLayoutMappings () {
286- Iterator <MethodOrMethodContext > rmIterator = Scene .v ().getReachableMethods ().listener ();
320+ if (rmIterator == null )
321+ rmIterator = Scene .v ().getReachableMethods ().listener ();
287322 while (rmIterator .hasNext ()) {
288323 SootMethod sm = rmIterator .next ().method ();
324+
289325 if (!sm .isConcrete ())
290326 continue ;
291327 if (SystemClassHandler .v ().isClassInSystemPackage (sm .getDeclaringClass ().getName ()))
292328 continue ;
293-
294- for (Unit u : sm .retrieveActiveBody ().getUnits ())
329+ RefType fragmentType = RefType . v ( "android.app.Fragment" );
330+ for (Unit u : sm .retrieveActiveBody ().getUnits ()) {
295331 if (u instanceof Stmt ) {
296332 Stmt stmt = (Stmt ) u ;
297333 if (stmt .containsInvokeExpr ()) {
298334 InvokeExpr inv = stmt .getInvokeExpr ();
299- if (invokesSetContentView (inv ) || invokesInflate ( inv ) ) { // check
300- // also
301- // for
302- // inflate
303- // to
304- // look
305- // for
306- // the
307- // fragments
335+ if (invokesSetContentView (inv )) { // check
336+ // also
337+ // for
338+ // inflate
339+ // to
340+ // look
341+ // for
342+ // the
343+ // fragments
308344 for (Value val : inv .getArgs ()) {
309345 Integer intValue = valueProvider .getValue (sm , stmt , val , Integer .class );
310- if (intValue != null )
346+ if (intValue != null ) {
311347 this .layoutClasses .put (sm .getDeclaringClass (), intValue );
348+ }
349+
350+ }
351+ }
352+ if (invokesInflate (inv )) {
353+ Integer intValue = valueProvider .getValue (sm , stmt , inv .getArg (0 ), Integer .class );
354+ if (intValue != null ) {
355+ this .layoutClasses .put (sm .getDeclaringClass (), intValue );
312356 }
313357 }
314358 }
315359 }
360+ }
316361 }
317362 }
318363
0 commit comments