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:
Tobias Blaschke 2014-02-13 20:59:57 +01:00 committed by Juergen Graf
parent 594447c18f
commit b963cc72bb
9 changed files with 229 additions and 21 deletions

View File

@ -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);
}
}

View File

@ -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();
}
/**

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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.
*

View File

@ -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;

View File

@ -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);