Skip to content

Commit 0591e79

Browse files
committed
Proper method management
1 parent 35c1b12 commit 0591e79

File tree

3 files changed

+139
-41
lines changed

3 files changed

+139
-41
lines changed

soot-infoflow-android/src/soot/jimple/infoflow/android/entryPointCreators/AndroidEntryPointCreator.java

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
******************************************************************************/
1111
package soot.jimple.infoflow.android.entryPointCreators;
1212

13+
import java.util.AbstractCollection;
1314
import java.util.ArrayList;
1415
import java.util.Arrays;
1516
import java.util.Collection;
@@ -142,6 +143,8 @@ public class AndroidEntryPointCreator extends AbstractAndroidEntryPointCreator i
142143
private SootMethod getIntentMethod;
143144
private SootMethod setIntentMethod;
144145

146+
private AbstractCollection<SootMethod> additionalMethods;
147+
145148
/**
146149
* Creates a new instance of the {@link AndroidEntryPointCreator} class and
147150
* registers a list of classes to be automatically scanned for Android lifecycle
@@ -220,38 +223,10 @@ protected SootMethod createDummyMainInternal() {
220223
// Make sure that we don't have any leftover state
221224
// from previous runs
222225
reset();
226+
additionalMethods = new HashSet<>();
223227

224228
logger.info(String.format("Creating Android entry point for %d components...", components.size()));
225229

226-
// For some weird reason unknown to anyone except the flying spaghetti
227-
// monster, the onCreate() methods of content providers run even before
228-
// the application object's onCreate() is called.
229-
{
230-
boolean hasContentProviders = false;
231-
NopStmt beforeContentProvidersStmt = Jimple.v().newNopStmt();
232-
body.getUnits().add(beforeContentProvidersStmt);
233-
for (SootClass currentClass : components) {
234-
if (entryPointUtils.getComponentType(currentClass) == ComponentType.ContentProvider) {
235-
// Create an instance of the content provider
236-
Local localVal = generateClassConstructor(currentClass);
237-
if (localVal == null)
238-
continue;
239-
localVarsForClasses.put(currentClass, localVal);
240-
241-
// Conditionally call the onCreate method
242-
NopStmt thenStmt = Jimple.v().newNopStmt();
243-
createIfStmt(thenStmt);
244-
searchAndBuildMethod(AndroidEntryPointConstants.CONTENTPROVIDER_ONCREATE, localVal);
245-
body.getUnits().add(thenStmt);
246-
hasContentProviders = true;
247-
}
248-
}
249-
// Jump back to the beginning of this section to overapproximate the
250-
// order in which the methods are called
251-
if (hasContentProviders)
252-
createIfStmt(beforeContentProvidersStmt);
253-
}
254-
255230
// If the application tag in the manifest specifies a appComponentFactory, it
256231
// needs to be called first
257232
initializeApplComponentFactory();
@@ -262,10 +237,12 @@ protected SootMethod createDummyMainInternal() {
262237
Jimple j = Jimple.v();
263238

264239
// due to app component factories, that could be another application class!
240+
// The application class gets instantiated first. Note that although it's
241+
// created now, it's onCreate method gets called *after*
242+
// all content providers.
265243
SootClass applicationClassUse = Scene.v().getSootClass(AndroidEntryPointConstants.APPLICATIONCLASS);
266-
;
267-
// If we have an application, we need to start it in the very beginning
268-
if (applicationClass != null || applicationComponentFactoryClass != null) {
244+
boolean generateApplicationCode = applicationClass != null || applicationComponentFactoryClass != null;
245+
if (generateApplicationCode) {
269246
if (applicationComponentFactoryClass != null) {
270247
Local factory = generateClassConstructor(applicationComponentFactoryClass);
271248
SootMethodRef mrInstantiate = Scene.v().makeMethodRef(
@@ -294,8 +271,10 @@ protected SootMethod createDummyMainInternal() {
294271
mrInstantiateClassLoader, Arrays.asList(classLoader, createApplicationInfo())));
295272
body.getUnits().add(instantiateCL);
296273

297-
classLoaderField = createField(RefType.v("java.lang.ClassLoader"), "cl");
298-
instantiatorField = createField(RefType.v("android.app.AppComponentFactory"), "cl");
274+
if (classLoaderField == null)
275+
classLoaderField = createField(RefType.v("java.lang.ClassLoader"), "cl");
276+
if (instantiatorField == null)
277+
instantiatorField = createField(RefType.v("android.app.AppComponentFactory"), "cl");
299278

300279
AssignStmt instantiate = j.newAssignStmt(applicationLocal, j.newVirtualInvokeExpr(factory,
301280
mrInstantiate, Arrays.asList(classLoader, StringConstant.v(classAppl))));
@@ -310,6 +289,41 @@ protected SootMethod createDummyMainInternal() {
310289
applicationClassUse = applicationClass;
311290
}
312291
localVarsForClasses.put(applicationClass, applicationLocal);
292+
}
293+
294+
Map<SootClass, ContentProviderEntryPointCreator> cpComponents = new HashMap<>();
295+
// For some weird reason unknown to anyone except the flying spaghetti
296+
// monster, the onCreate() methods of content providers run even before
297+
// the application object's onCreate() is called (but after the creation of the
298+
// application).
299+
// See https://issuetracker.google.com/issues/36917845#comment4
300+
{
301+
boolean hasContentProviders = false;
302+
NopStmt beforeContentProvidersStmt = Jimple.v().newNopStmt();
303+
body.getUnits().add(beforeContentProvidersStmt);
304+
for (SootClass currentClass : components) {
305+
if (entryPointUtils.getComponentType(currentClass) == ComponentType.ContentProvider) {
306+
// Create an instance of the content provider
307+
ContentProviderEntryPointCreator cpc = new ContentProviderEntryPointCreator(currentClass,
308+
applicationClassUse, this.manifest, instantiatorField, classLoaderField,
309+
componentToInfo.getComponentExchangeInfo());
310+
SootMethod m = cpc.createInit();
311+
Local cpLocal = generator.generateLocal(RefType.v(AndroidEntryPointConstants.CONTENTPROVIDERCLASS));
312+
body.getUnits().add(Jimple.v().newAssignStmt(cpLocal, Jimple.v().newStaticInvokeExpr(m.makeRef())));
313+
localVarsForClasses.put(currentClass, cpLocal);
314+
cpComponents.put(currentClass, cpc);
315+
316+
hasContentProviders = true;
317+
}
318+
}
319+
// Jump back to the beginning of this section to overapproximate the
320+
// order in which the methods are called
321+
if (hasContentProviders)
322+
createIfStmt(beforeContentProvidersStmt);
323+
}
324+
325+
// If we have an application, we need to start it in the very beginning
326+
if (generateApplicationCode) {
313327
if (applicationLocal != null) {
314328
boolean hasApplicationCallbacks = applicationCallbackClasses != null
315329
&& !applicationCallbackClasses.isEmpty();
@@ -395,6 +409,7 @@ protected SootMethod createDummyMainInternal() {
395409
// Generate the lifecycles for the different kinds of Android
396410
// classes
397411
AbstractComponentEntryPointCreator componentCreator = null;
412+
List<Value> params = Collections.singletonList(NullConstant.v());
398413
switch (componentType) {
399414
case Activity:
400415
Map<SootClass, SootMethod> curActivityToFragmentMethod = new HashMap<>();
@@ -425,8 +440,9 @@ protected SootMethod createDummyMainInternal() {
425440
this.manifest, instantiatorField, classLoaderField, componentToInfo.getComponentExchangeInfo());
426441
break;
427442
case ContentProvider:
428-
componentCreator = new ContentProviderEntryPointCreator(currentClass, applicationClassUse,
429-
this.manifest, instantiatorField, classLoaderField, componentToInfo.getComponentExchangeInfo());
443+
componentCreator = cpComponents.get(currentClass);
444+
//We need to pass on the content provider instance
445+
params = Arrays.asList(NullConstant.v(), localVarsForClasses.get(currentClass));
430446
break;
431447
default:
432448
componentCreator = null;
@@ -443,11 +459,11 @@ protected SootMethod createDummyMainInternal() {
443459
SootMethod lifecycleMethod = componentCreator.createDummyMain();
444460
componentToInfo.put(currentClass, componentCreator.getComponentInfo());
445461

462+
additionalMethods.addAll(componentCreator.getAdditionalMethods());
446463
// dummyMain(component, intent)
447464
if (shouldAddLifecycleCall(currentClass)) {
448-
body.getUnits()
449-
.add(Jimple.v().newInvokeStmt(Jimple.v().newStaticInvokeExpr(lifecycleMethod.makeRef(),
450-
Collections.singletonList(NullConstant.v()))));
465+
body.getUnits().add(Jimple.v()
466+
.newInvokeStmt(Jimple.v().newStaticInvokeExpr(lifecycleMethod.makeRef(), params)));
451467
}
452468
}
453469

@@ -853,7 +869,10 @@ public void setFragments(MultiMap<SootClass, SootClass> fragments) {
853869

854870
@Override
855871
public Collection<SootMethod> getAdditionalMethods() {
856-
return componentToInfo.getLifecycleMethods();
872+
List<SootMethod> r = new ArrayList<>(componentToInfo.getLifecycleMethods());
873+
if (additionalMethods != null)
874+
r.addAll(additionalMethods);
875+
return r;
857876
}
858877

859878
@Override

soot-infoflow-android/src/soot/jimple/infoflow/android/entryPointCreators/components/AbstractComponentEntryPointCreator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ protected SootMethod createDummyMainInternal() {
193193
createIfStmt(endClassStmt);
194194

195195
// Create a new instance of the component
196-
thisLocal = generateClassConstructor(component);
196+
if (thisLocal == null)
197+
thisLocal = generateClassConstructor(component);
197198
if (thisLocal != null) {
198199
localVarsForClasses.put(component, thisLocal);
199200

soot-infoflow-android/src/soot/jimple/infoflow/android/entryPointCreators/components/ContentProviderEntryPointCreator.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
package soot.jimple.infoflow.android.entryPointCreators.components;
22

3+
import java.lang.reflect.Modifier;
4+
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.Collection;
7+
import java.util.Collections;
8+
import java.util.List;
9+
10+
import soot.Body;
311
import soot.Local;
12+
import soot.RefType;
413
import soot.Scene;
514
import soot.SootClass;
615
import soot.SootField;
716
import soot.SootMethod;
17+
import soot.Type;
818
import soot.UnitPatchingChain;
19+
import soot.javaToJimple.DefaultLocalGenerator;
920
import soot.jimple.Jimple;
1021
import soot.jimple.NopStmt;
1122
import soot.jimple.infoflow.android.entryPointCreators.AndroidEntryPointConstants;
@@ -21,11 +32,78 @@
2132
*/
2233
public class ContentProviderEntryPointCreator extends AbstractComponentEntryPointCreator {
2334

35+
private SootMethod initMethod;
36+
private String initCPMethodName = "initCP";
37+
2438
public ContentProviderEntryPointCreator(SootClass component, SootClass applicationClass, IManifestHandler manifest,
2539
SootField instantiatorField, SootField classLoaderField, ComponentExchangeInfo componentExchangeInfo) {
2640
super(component, applicationClass, manifest, instantiatorField, classLoaderField, componentExchangeInfo);
2741
}
2842

43+
public SootMethod createInit() {
44+
SootMethod m = createEmptyInitMethod();
45+
body = m.retrieveActiveBody();
46+
generator = new DefaultLocalGenerator(body);
47+
Local l = generateClassConstructor(component);
48+
searchAndBuildMethod(AndroidEntryPointConstants.CONTENTPROVIDER_ONCREATE, l);
49+
50+
body.getUnits().add(Jimple.v().newReturnStmt(l));
51+
//make sure the body doesn't get used when creating the actual dummy main
52+
body = null;
53+
generator = null;
54+
return m;
55+
}
56+
57+
@Override
58+
protected List<Type> getAdditionalMainMethodParams() {
59+
return Arrays.asList(RefType.v(AndroidEntryPointConstants.CONTENTPROVIDERCLASS));
60+
}
61+
62+
private SootMethod createEmptyInitMethod() {
63+
int methodIndex = 0;
64+
String methodName = initCPMethodName;
65+
SootClass mainClass = getOrCreateDummyMainClass();
66+
while (mainClass.declaresMethodByName(methodName))
67+
methodName = initCPMethodName + "_" + methodIndex++;
68+
69+
Body body;
70+
71+
// Create the method
72+
SootMethod initMethod = Scene.v().makeSootMethod(methodName, Collections.emptyList(),
73+
RefType.v(AndroidEntryPointConstants.CONTENTPROVIDERCLASS));
74+
75+
// Create the body
76+
body = Jimple.v().newBody();
77+
body.setMethod(initMethod);
78+
initMethod.setActiveBody(body);
79+
80+
// Add the method to the class
81+
mainClass.addMethod(initMethod);
82+
83+
// First add class to scene, then make it an application class
84+
// as addClass contains a call to "setLibraryClass"
85+
mainClass.setApplicationClass();
86+
initMethod.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
87+
88+
this.initMethod = initMethod;
89+
return initMethod;
90+
}
91+
92+
@Override
93+
public Collection<SootMethod> getAdditionalMethods() {
94+
List<SootMethod> list = new ArrayList<>(super.getAdditionalMethods());
95+
if (initMethod != null)
96+
list.add(initMethod);
97+
return list;
98+
}
99+
100+
@Override
101+
protected void createEmptyMainMethod() {
102+
super.createEmptyMainMethod();
103+
//the parameter with the content provider local
104+
thisLocal = mainMethod.getActiveBody().getParameterLocal(1);
105+
}
106+
29107
@Override
30108
protected Local generateClassConstructor(SootClass createdClass) {
31109
if (createdClass == component && instantiatorField != null) {

0 commit comments

Comments
 (0)