Flatten Android-Component instances
Throw instances of android components into AndroidModelClass and reuse them. This resembles Android a bit more.
This commit is contained in:
parent
594447c18f
commit
b963cc72bb
|
@ -86,6 +86,7 @@ import com.ibm.wala.dalvik.ipa.callgraph.androidModel.structure.AbstractAndroidM
|
|||
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidBoot;
|
||||
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidStartComponentTool;
|
||||
|
||||
import com.ibm.wala.classLoader.IField;
|
||||
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
import com.ibm.wala.dalvik.util.AndroidTypes;
|
||||
|
@ -618,6 +619,11 @@ public class AndroidModel /* makes SummarizedMethod */
|
|||
final ParameterAccessor acc = new ParameterAccessor(asMethod, /* hasImplicitThis: */ true);
|
||||
//final AndroidModelParameterManager pm = new AndroidModelParameterManager(acc);
|
||||
final SSAValueManager pm = new SSAValueManager(acc);
|
||||
if (callerNd != null) {
|
||||
pm.breadCrumb = "Caller: " + caller + " Context: " + callerNd.getContext() + " Model: " + this.getClass() + " Name: " + this.getName();
|
||||
} else {
|
||||
pm.breadCrumb = "Caller: " + caller + " Model: " + this.getClass();
|
||||
}
|
||||
final VolatileMethodSummary redirect = new VolatileMethodSummary(new MethodSummary(asMethod));
|
||||
redirect.setStatic(false);
|
||||
final Parameter self = acc.getThis();
|
||||
|
@ -648,8 +654,28 @@ public class AndroidModel /* makes SummarizedMethod */
|
|||
if (inAsMethod != null) {
|
||||
allActivities.add(inAsMethod);
|
||||
} else {
|
||||
final SSAValue newInstance = instantiator.createInstance(activityType, false, null, null);
|
||||
allActivities.add(newInstance);
|
||||
final Atom fdName = activityType.getName().getClassName();
|
||||
final AndroidModelClass mClass = AndroidModelClass.getInstance(cha);
|
||||
|
||||
if (mClass.getField(fdName) != null) {
|
||||
final IField field = mClass.getField(fdName);
|
||||
final int instPC = redirect.getNextProgramCounter();
|
||||
final SSAValue target = pm.getUnallocated(activityType, new SSAValue.WeaklyNamedKey(activityType.getName(),
|
||||
"got" + fdName.toString()));
|
||||
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, target, field.getReference());
|
||||
redirect.addStatement(getInst);
|
||||
pm.setAllocation(target, getInst);
|
||||
allActivities.add(target);
|
||||
} else {
|
||||
final SSAValue newInstance = instantiator.createInstance(activityType, false, null, null);
|
||||
allActivities.add(newInstance);
|
||||
|
||||
mClass.putField(fdName, activityType);
|
||||
final int instPC = redirect.getNextProgramCounter();
|
||||
final FieldReference fdRef = FieldReference.findOrCreate(mClass.getReference(), fdName, activityType);
|
||||
final SSAInstruction putInst = instructionFactory.PutInstruction(instPC, newInstance, fdRef);
|
||||
redirect.addStatement(putInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(allActivities.size() == modelsActivities.size());
|
||||
|
@ -844,6 +870,7 @@ public class AndroidModel /* makes SummarizedMethod */
|
|||
final TypeSafeInstructionFactory instructionFactory = new TypeSafeInstructionFactory(getClassHierarchy());
|
||||
final ParameterAccessor acc = new ParameterAccessor(asMethod, /* hasImplicitThis: */ false);
|
||||
final SSAValueManager pm = new SSAValueManager(acc);
|
||||
pm.breadCrumb = "Encap: " + this.getClass().toString();
|
||||
final SummarizedMethod model = getMethod();
|
||||
|
||||
final List<SSAValue> params = new ArrayList<SSAValue>();
|
||||
|
@ -852,9 +879,34 @@ public class AndroidModel /* makes SummarizedMethod */
|
|||
|
||||
for (int i = 0; i < model.getNumberOfParameters(); ++i) {
|
||||
final TypeReference argT = model.getParameterType(i);
|
||||
final boolean managed = false;
|
||||
final SSAValue.VariableKey key = new SSAValue.TypeKey(argT.getName());
|
||||
final SSAValue arg = instantiator.createInstance (argT, managed, key, null);
|
||||
final SSAValue arg;
|
||||
|
||||
if (AndroidComponent.isAndroidComponent(argT, cha)) {
|
||||
// Get / Put filed in AndroidModelClass for Android-Components
|
||||
final Atom fdName = argT.getName().getClassName();
|
||||
|
||||
if (mClass.getField(fdName) != null) {
|
||||
final IField field = mClass.getField(fdName);
|
||||
final int instPC = encap.getNextProgramCounter();
|
||||
arg = pm.getUnallocated(argT, new SSAValue.WeaklyNamedKey(argT.getName(),
|
||||
"got" + fdName.toString()));
|
||||
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, arg, field.getReference());
|
||||
encap.addStatement(getInst);
|
||||
pm.setAllocation(arg, getInst);
|
||||
} else {
|
||||
arg = instantiator.createInstance(argT, false, null, null);
|
||||
|
||||
mClass.putField(fdName, argT);
|
||||
final int instPC = encap.getNextProgramCounter();
|
||||
final FieldReference fdRef = FieldReference.findOrCreate(mClass.getReference(), fdName, argT);
|
||||
final SSAInstruction putInst = instructionFactory.PutInstruction(instPC, arg, fdRef);
|
||||
encap.addStatement(putInst);
|
||||
}
|
||||
} else {
|
||||
final boolean managed = false;
|
||||
final SSAValue.VariableKey key = new SSAValue.TypeKey(argT.getName());
|
||||
arg = instantiator.createInstance (argT, managed, key, null);
|
||||
}
|
||||
params.add(arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,9 @@ import com.ibm.wala.util.collections.HashSetFactory;
|
|||
import com.ibm.wala.util.debug.Assertions;
|
||||
import com.ibm.wala.util.debug.UnimplementedError;
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
import com.ibm.wala.classLoader.FieldImpl;
|
||||
|
||||
import com.ibm.wala.shrikeCT.ClassConstants;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -64,6 +67,8 @@ import java.util.List;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Encapsulates synthetic methods for modeling Androids lifecycle.
|
||||
|
@ -188,13 +193,23 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass {
|
|||
// Contents of the class: Fields
|
||||
// We have none...
|
||||
//
|
||||
private Map<Atom, IField> fields = new HashMap<Atom, IField>();
|
||||
|
||||
/**
|
||||
* This class does not contain any fields.
|
||||
*/
|
||||
@Override
|
||||
public IField getField(Atom name) {
|
||||
return null;
|
||||
if (fields.containsKey(name)) {
|
||||
return fields.get(name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void putField(Atom name, TypeReference type) {
|
||||
final FieldReference fdRef = FieldReference.findOrCreate(this.getReference(), name, type);
|
||||
final int accessFlags = ClassConstants.ACC_STATIC | ClassConstants.ACC_PUBLIC;
|
||||
final IField field = new FieldImpl(this, fdRef, accessFlags, null);
|
||||
|
||||
this.fields.put(name, field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,7 +217,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass {
|
|||
*/
|
||||
@Override
|
||||
public Collection<IField> getAllFields() {
|
||||
return Collections.emptySet();
|
||||
return fields.values();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +225,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass {
|
|||
*/
|
||||
@Override
|
||||
public Collection<IField> getDeclaredStaticFields() {
|
||||
return Collections.emptySet();
|
||||
return fields.values();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,7 +233,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass {
|
|||
*/
|
||||
@Override
|
||||
public Collection<IField> getAllStaticFields() {
|
||||
return Collections.emptySet();
|
||||
return fields.values();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -158,7 +158,6 @@ public class FlatInstantiator implements IInstantiator {
|
|||
}
|
||||
|
||||
if (currentDepth > this.maxDepth) {
|
||||
System.out.println("Depth-Limit exceeded for: " + T); // TODO: Remove
|
||||
final SSAValue instance = this.pm.getUnmanaged(T, key);
|
||||
instance.setAssigned();
|
||||
return instance;
|
||||
|
|
|
@ -75,6 +75,10 @@ import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
|||
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
|
||||
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.AndroidModelClass;
|
||||
import com.ibm.wala.classLoader.IField;
|
||||
import com.ibm.wala.util.strings.Atom;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -158,7 +162,26 @@ public class Instantiator implements IInstantiator {
|
|||
instance = this.pm.getUnmanaged(T, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // Try fetch Android-Components from AndroidModelClass
|
||||
if (com.ibm.wala.dalvik.util.AndroidComponent.isAndroidComponent(T, cha)) {
|
||||
final AndroidModelClass mClass = AndroidModelClass.getInstance(cha);
|
||||
final Atom fdName = T.getName().getClassName();
|
||||
|
||||
if (mClass.getField(fdName) != null) {
|
||||
final IField field = mClass.getField(fdName);
|
||||
final int instPC = this.body.getNextProgramCounter();
|
||||
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, instance, field.getReference());
|
||||
this.body.addStatement(getInst);
|
||||
pm.setAllocation(instance, getInst);
|
||||
return instance;
|
||||
} else {
|
||||
System.out.println("NEW Component " + instance + "\n\tbreadCrumb: " + pm.breadCrumb);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
} // */
|
||||
|
||||
if (T.isPrimitiveType()) {
|
||||
createPrimitive(instance);
|
||||
return instance;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
package com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs;
|
||||
|
||||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.classLoader.CallSiteReference;
|
||||
import com.ibm.wala.types.FieldReference;
|
||||
import com.ibm.wala.types.MethodReference;
|
||||
|
@ -248,12 +249,16 @@ public class AndroidStartComponentTool {
|
|||
logger.warn("Asking for context when Context-Free");
|
||||
return null; // XXX: Return a synthetic null?
|
||||
}*/
|
||||
|
||||
logger.debug("Fetching caller context...");
|
||||
final SSAValue androidContext;
|
||||
if (caller == null) {
|
||||
return null;
|
||||
} else if (caller.getName().equals(AndroidTypes.ContextWrapperName)) {
|
||||
}
|
||||
|
||||
final IClass iCaller = cha.lookupClass(caller);
|
||||
final IClass iActivity = cha.lookupClass(AndroidTypes.Activity);
|
||||
|
||||
logger.debug("Fetching caller context...");
|
||||
final SSAValue androidContext;
|
||||
if (caller.getName().equals(AndroidTypes.ContextWrapperName)) {
|
||||
{ // Fetch ContextWrapperName.mBase => androidContext
|
||||
androidContext = pm.getUnmanaged(AndroidTypes.Context, "callerContext");
|
||||
logger.debug("Fetching ContextWrapperName.mBase");
|
||||
|
@ -276,7 +281,7 @@ public class AndroidStartComponentTool {
|
|||
logger.info("Caller has android-context type: ContextImpl");
|
||||
return androidContext;
|
||||
}
|
||||
} else if (caller.getName().equals(AndroidTypes.ActivityName)) {
|
||||
} else if (cha.isAssignableFrom(iActivity, iCaller)) {
|
||||
// We don't need it for now - TODO grab anyway
|
||||
androidContext = null;
|
||||
this.callerContext = AndroidTypes.AndroidContextType.ACTIVITY;
|
||||
|
@ -349,7 +354,8 @@ public class AndroidStartComponentTool {
|
|||
|
||||
logger.info("The context to use for the call is from an IBinder");
|
||||
return iBinder;
|
||||
} else if (caller.getName().equals(AndroidTypes.ActivityName)) {
|
||||
//} else if (caller.getName().equals(AndroidTypes.ActivityName)) {
|
||||
} else if (this.callerContext == AndroidTypes.AndroidContextType.ACTIVITY) {
|
||||
|
||||
// The IBinder is Activity.mMainThread.getApplicationThread() // TODO: Verify
|
||||
final SSAValue mMainThread = pm.getUnmanaged(AndroidTypes.ActivityThread, "callersMainThred");
|
||||
|
|
|
@ -53,6 +53,7 @@ import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
|||
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||
import com.ibm.wala.ssa.IR;
|
||||
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||
import com.ibm.wala.ipa.callgraph.ContextKey;
|
||||
import com.ibm.wala.types.ClassLoaderReference;
|
||||
|
||||
import com.ibm.wala.classLoader.IMethod;
|
||||
|
@ -70,6 +71,8 @@ import com.ibm.wala.ssa.DefUse;
|
|||
import com.ibm.wala.classLoader.IClass;
|
||||
import com.ibm.wala.types.FieldReference;
|
||||
|
||||
import com.ibm.wala.ipa.callgraph.propagation.AbstractTypeInNode;
|
||||
|
||||
import java.util.Iterator;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import java.util.Set;
|
||||
|
@ -138,7 +141,23 @@ public class IntentContextInterpreter implements SSAContextInterpreter {
|
|||
final Intent intent = AndroidEntryPointManager.MANAGER.getIntent(inIntent); // Apply overrides
|
||||
final Atom target = intent.action;
|
||||
final IMethod method = node.getMethod();
|
||||
final TypeReference callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit!
|
||||
final TypeReference callingClass;
|
||||
{
|
||||
if (ctx.get(ContextKey.CALLER) != null) {
|
||||
System.out.println("CALLER CONTEXT" + ctx.get(ContextKey.CALLER));
|
||||
callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit!
|
||||
} else if (ctx.get(ContextKey.CALLSITE) != null) {
|
||||
System.out.println("CALLSITE CONTEXT" + ctx.get(ContextKey.CALLSITE));
|
||||
callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit!
|
||||
} else if (ctx.get(ContextKey.RECEIVER) != null) {
|
||||
//System.out.println("RECEIVER CONTEXT" + ctx.get(ContextKey.RECEIVER).getClass());
|
||||
final AbstractTypeInNode aType = (AbstractTypeInNode) ctx.get(ContextKey.RECEIVER);
|
||||
callingClass = aType.getConcreteType().getReference();
|
||||
} else {
|
||||
callingClass = node.getMethod().getReference().getDeclaringClass(); // TODO: This may not necessarily fit!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final Intent.IntentType type = intent.getType();
|
||||
final IR ir;
|
||||
|
|
|
@ -113,6 +113,28 @@ public enum AndroidComponent {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isAndroidComponent(final TypeReference T, final IClassHierarchy cha) {
|
||||
for (final AndroidComponent candid : AndroidComponent.values()) {
|
||||
if (candid == AndroidComponent.UNKNOWN) continue;
|
||||
if (candid.getName().equals(T.getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final IClass iT = cha.lookupClass(T);
|
||||
final IClass iCand = cha.lookupClass(candid.toReference());
|
||||
if (iT == null) {
|
||||
return false; // TODO
|
||||
}
|
||||
if (iCand == null) {
|
||||
return false; // ???!!!
|
||||
}
|
||||
if (cha.isAssignableFrom(iCand, iT)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A name usable for display-output.
|
||||
*
|
||||
|
|
|
@ -80,6 +80,9 @@ public class SSAValueManager {
|
|||
private String description;
|
||||
private MethodReference forMethod;
|
||||
|
||||
/** User-Defined debugging info */
|
||||
public String breadCrumb = "";
|
||||
|
||||
private static class Managed<T extends SSAValue> {
|
||||
public ValueStatus status = ValueStatus.UNUSED;
|
||||
public SSAInstruction setBy = null;
|
||||
|
|
|
@ -396,6 +396,41 @@ public class TypeSafeInstructionFactory {
|
|||
return insts.GetInstruction(iindex, targetValue.getNumber(), containingInstance.getNumber(), field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads static field into targetValue.
|
||||
*
|
||||
* If type check passes the corresponding GetInstruction of the JavaInstructionFactory is called.
|
||||
* Calls targetValue.setAssigned()
|
||||
*
|
||||
* @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.GetInstruction(int, int, int, FieldReference)
|
||||
*
|
||||
* @param iindex Zero or a positive number unique to any instruction of the same method
|
||||
* @param targetValue the result of the GetInstruction is placed there
|
||||
* @param containingInstance The Object instance to read the field from
|
||||
* @param field The description of the field
|
||||
*/
|
||||
public SSAGetInstruction GetInstruction(final int iindex, final SSAValue targetValue, FieldReference field) {
|
||||
logger.info("Now: Get {} into {}", field, targetValue);
|
||||
|
||||
if (iindex < 0) {
|
||||
throw new IllegalArgumentException("iIndex may not be negative");
|
||||
}
|
||||
if (targetValue == null) {
|
||||
throw new IllegalArgumentException("targetValue may not be null");
|
||||
}
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("field may not be null");
|
||||
}
|
||||
if (! isAssignableFrom(field.getFieldType(), targetValue.getType())) {
|
||||
throw new IllegalArgumentException("The field " + targetValue + " is not assignable from " + field);
|
||||
}
|
||||
|
||||
targetValue.setAssigned();
|
||||
return insts.GetInstruction(iindex, targetValue.getNumber(), field);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes newValue to field of targetInstance.
|
||||
*
|
||||
|
@ -443,6 +478,40 @@ public class TypeSafeInstructionFactory {
|
|||
return insts.PutInstruction(iindex, targetInstance.getNumber(), newValue.getNumber(), field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes newValue to static field.
|
||||
*
|
||||
* If type check passes the corresponding PutInstruction of the JavaInstructionFactory is called.
|
||||
*
|
||||
* @see com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory.PutInstruction(int, int, int, FieldReference)
|
||||
*
|
||||
* @param iindex Zero or a psitive number unique to any instruction of the same method
|
||||
* @param targetInstance the instance of the object to write a field of
|
||||
* @param newValue The value to write to the field
|
||||
* @param field The description of the target
|
||||
*/
|
||||
public SSAPutInstruction PutInstruction(final int iindex, final SSAValue newValue, FieldReference field) {
|
||||
logger.info("Now: Put {} to {}", newValue, field);
|
||||
|
||||
if (iindex < 0) {
|
||||
throw new IllegalArgumentException("iIndex may not be negative");
|
||||
}
|
||||
if (newValue == null) {
|
||||
throw new IllegalArgumentException("newValue may not be null");
|
||||
}
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("field may not be null");
|
||||
}
|
||||
if (! isAssignableFrom(newValue.getType(), field.getFieldType())) {
|
||||
throw new IllegalArgumentException("The field " + field + " is not assignable from " + newValue);
|
||||
}
|
||||
|
||||
final MethodReference newValueValidIn = newValue.getValidIn();
|
||||
|
||||
return insts.PutInstruction(iindex, newValue.getNumber(), field);
|
||||
}
|
||||
|
||||
|
||||
public SSANewInstruction NewInstruction(int iindex, SSAValue result, NewSiteReference site) {
|
||||
logger.info("Now: New {}", result);
|
||||
|
||||
|
|
Loading…
Reference in New Issue