Make Intents immutable when attached to Context

Oops.
Fixes in intent-Resolution
This commit is contained in:
Tobias Blaschke 2014-03-02 16:46:49 +01:00 committed by Juergen Graf
parent 8e7d44f6dc
commit 851594cff5
6 changed files with 89 additions and 20 deletions

View File

@ -510,7 +510,7 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
public IntSet getPossibleTargetNumbers(CGNode node, CallSiteReference site) {
if (!containsNode(node)) {
throw new IllegalArgumentException("node not in callgraph " + node);
throw new IllegalArgumentException("node not in callgraph " + node + " Site: " + site);
}
assert (node instanceof ExplicitNode);
ExplicitNode n = (ExplicitNode) node;

View File

@ -261,7 +261,9 @@ public class AndroidStartComponentTool {
logger.debug("Fetching caller context...");
final SSAValue androidContext;
if (caller.getName().equals(AndroidTypes.ContextWrapperName)) {
{ // Fetch ContextWrapperName.mBase => androidContext
this.callerContext = AndroidTypes.AndroidContextType.USELESS;
return null;
/*{ // Fetch ContextWrapperName.mBase => androidContext
androidContext = pm.getUnmanaged(AndroidTypes.Context, "callerContext");
logger.debug("Fetching ContextWrapperName.mBase");
@ -275,7 +277,7 @@ public class AndroidStartComponentTool {
this.callerContext = AndroidTypes.AndroidContextType.CONTEXT_IMPL;
logger.info("Caller has android-context type: ContextWrapper(ContextImpl)");
return androidContext;
}
} */
} else if (caller.getName().equals(AndroidTypes.ContextImplName)) {
{ // self is already the right context
androidContext = self;

View File

@ -74,7 +74,7 @@ import org.slf4j.LoggerFactory;
* @author Tobias Blaschke <code@tobiasblaschke.de>
* @since 2013-10-12
*/
public class Intent implements ContextItem {
public class Intent implements ContextItem, Comparable<Intent> {
private static final Logger logger = LoggerFactory.getLogger(Intent.class);
/**
@ -112,6 +112,7 @@ public class Intent implements ContextItem {
private IntentType type;
private Explicit explicit = Explicit.UNSET;
private AndroidComponent targetCompontent; // Activity, Service, ...
private boolean immutable = false;
public Intent() {
this.action = null;
@ -152,6 +153,19 @@ public class Intent implements ContextItem {
return explicit == Explicit.EXPLICIT;
}
public void setImmutable() {
this.immutable = true;
}
public Intent clone() {
final Intent clone = new Intent();
clone.action = this.action; // OK here?
clone.uri = this.uri;
clone.type = this.type;
clone.explicit = this.explicit;
clone.targetCompontent = this.targetCompontent;
return clone;
}
/**
@ -166,6 +180,7 @@ public class Intent implements ContextItem {
if (this.action == null) {
assert (this.explicit == Explicit.UNSET) : "No Action but Intent is not UNSET - is " + this.explicit;
assert (! immutable) : "Intent was marked immutable - can't change it.";
this.action = action;
this.explicit = Explicit.EXPLICIT;
logger.info("Intent({})", action);
@ -175,6 +190,7 @@ public class Intent implements ContextItem {
unbind();
} else if (! isExplicit() ) {
logger.warn("Making implicit Intent {} explictit! Target: {}", this, action);
assert (! immutable) : "Intent was marked immutable - can't change it.";
this.action = action;
this.explicit = Explicit.EXPLICIT;
// TODO: Set type?
@ -185,6 +201,7 @@ public class Intent implements ContextItem {
public void unbind() {
assert (! immutable) : "Intent was marked immutable - can't change it.";
this.action = UNBOUND;
this.type = IntentType.UNKNOWN_TARGET;
this.explicit = Explicit.MULTI; // XXX shoulb we do this?
@ -197,6 +214,7 @@ public class Intent implements ContextItem {
*/
public void setAction(Atom action) {
if (this.action == null) {
assert (! immutable) : "Intent was marked immutable - can't change it.";
this.action = action;
logger.info("Intent({})", action);
} else if (isExplicit()) {
@ -218,7 +236,9 @@ public class Intent implements ContextItem {
if (this.type != null) {
return this.type;
} else {
if (isStandardAction(this)) {
if (isSystemService(this)) {
this.type = IntentType.SYSTEM_SERVICE;
} else if (isStandardAction(this)) {
this.type = IntentType.STANDARD_ACTION;
} else if (isInternal(this)) {
this.type = IntentType.INTERNAL_TARGET;
@ -245,6 +265,11 @@ public class Intent implements ContextItem {
return this.targetCompontent;
}
private static boolean isSystemService(Intent intent) {
assert (intent.action != null);
return ((intent.action.getVal(0) != 'L') && (intent.action.rIndex((byte) '/') < 0) && (intent.action.rIndex((byte) '.') < 0));
}
/**
* Fallback: tries to determine on the Intent itself if it's internal.
*
@ -417,13 +442,22 @@ public class Intent implements ContextItem {
// DO NOT USE TYPE!
if (this.uri != null) {
return ( (this.uri.equals(other.uri)) && equalAction(other));
return ( (this.uri.equals(other.uri)) && equalAction(other) ); // && (this.explicit == other.explicit));
} else {
return ( (other.uri == null) && equalAction(other) ) ;
return ( (other.uri == null) && equalAction(other) ); // && (this.explicit == other.explicit)) ;
}
} else {
System.err.println("WARNING: Can't compare Intent to " + o.getClass());
return false;
}
}
public Intent resolve() {
return AndroidEntryPointManager.MANAGER.getIntent(this);
}
@Override
public int compareTo(Intent other) {
return getAction().toString().compareTo(other.getAction().toString());
}
}

View File

@ -123,9 +123,14 @@ public class IntentContextInterpreter implements SSAContextInterpreter {
/**
* Read possible targets of the intents Infos.
*/
private AndroidComponent fetchTargetComponent(final Intent intent, final IMethod method) {
private AndroidComponent fetchTargetComponent(final Intent intent, final IMethod method) {
assert (method != null);
assert (intentStarters.getInfo(method.getReference()) != null) : "No IntentStarter for Method " + method + " " + intent;
if (intent.getComponent() != null) {
return intent.getComponent();
} else if (intent.getType() == Intent.IntentType.SYSTEM_SERVICE) {
logger.error("Called fetchTargetComponent on a SystemService");
return null;
} else {
final Set<AndroidComponent> possibleTargets = intentStarters.getInfo(method.getReference()).getComponentsPossible();
if (possibleTargets.size() == 1) {

View File

@ -126,6 +126,7 @@ public class IntentContextSelector implements ContextSelector {
if (this.parent != null) {
ctx = parent.getCalleeTarget(caller, site, callee, actualParameters);
assert (ctx.get(Intent.INTENT_KEY) == null) : "Already have Intent: " + ctx + " caller " + caller + " callee " + callee;
}
if (intentStarters.isStarter(callee.getReference())) {
@ -165,13 +166,17 @@ public class IntentContextSelector implements ContextSelector {
// Add the context
if (intent != null) {
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
return new IntentContext(ctx, intent);
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
final Intent iintent = intents.findOrCreateImmutable(intent);
return new IntentContext(ctx, iintent);
//return new IntentContext(iintent);
} else {
logger.warn("Encountered unresolvable Intent");
intent = new Intent("Unresolvable");
intent.setImmutable();
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
return new IntentContext(ctx, intent);
//return new IntentContext(intent);
}
} else if (callee.getReference().toString().contains("getSystemService")) {
assert(actualParameters.length == 2) : "PARAMS LENGTH IS" + actualParameters.length;
@ -202,7 +207,9 @@ public class IntentContextSelector implements ContextSelector {
if (intent != null) {
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
logger.info("SystemService {} in {} by {}", intent, site, caller);
return new IntentContext(ctx, intent);
final Intent iintent = intents.findOrCreateImmutable(intent);
return new IntentContext(ctx, iintent);
//return new IntentContext(iintent);
}
} else if (callee.isInit() && callee.getDeclaringClass().getName().equals(AndroidTypes.IntentName)) {
//
@ -302,18 +309,20 @@ public class IntentContextSelector implements ContextSelector {
final InstanceKey actionKey = actualParameters[1];
final Intent intent = intents.find(self);
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
// Also we _could_ set the new target this is probably a bad idea: If setAction is called
// from a branch in execution the original target could still be called.
// We should implement intents, that can have multiple targets.
intents.setAction(self, actionKey, false); // May unbind internally
//intents.unbind(self);
if (AndroidEntryPointManager.MANAGER.isAllowIntentRerouting()) {
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intents.setAction(self, actionKey, false); // May unbind internally
} else {
intents.unbind(self);
}
logger.info("Encountered Intent.setAction - Intent is now: {}", intent);
} else if (callee.getSelector().equals(Selector.make("setComponent(Landroid/content/ComponentName;)Landroid/content/Intent;"))) {
// TODO: We can't extract from ComponentName yet.
final InstanceKey self = actualParameters[0];
final Intent intent = intents.find(self);
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intent.setExplicit();
intents.unbind(self);
} else if (callee.getSelector().equals(Selector.make("setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent;")) ||
@ -323,8 +332,13 @@ public class IntentContextSelector implements ContextSelector {
final InstanceKey actionKey = actualParameters[2];
final Intent intent = intents.find(self);
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intents.setAction(self, actionKey, true);
if (AndroidEntryPointManager.MANAGER.isAllowIntentRerouting()) {
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intents.setAction(self, actionKey, true);
} else {
intents.unbind(self);
}
logger.info("Encountered Intent.setClass - Intent is now: {}", intent);
} else if (callee.getSelector().equals(Selector.make("fillIn(Landroid/content/Intent;I)I"))) {
// See 'setAction' before... TODO
logger.warn("Intent.fillIn not implemented - Caller: {}", caller);

View File

@ -54,8 +54,22 @@ import org.slf4j.LoggerFactory;
/*package*/ class IntentMap {
private static final Logger logger = LoggerFactory.getLogger(IntentContextSelector.class);
/* package */ final Map<InstanceKey, Intent> seen = new HashMap<InstanceKey, Intent>();
private final Map<InstanceKey, Intent> seen = new HashMap<InstanceKey, Intent>();
private final Map<Intent, Intent> immutables = new HashMap<Intent, Intent>();
public Intent findOrCreateImmutable(final Intent intent) {
if (immutables.containsKey(intent)) {
final Intent immutable = immutables.get(intent);
assert (immutable.getAction().equals(intent.getAction()));
return immutable;
} else {
final Intent immutable = intent.clone();
immutable.setImmutable();
immutables.put(intent, immutable);
logger.debug("Now {} immutables", immutables.size());
return immutable;
}
}
public Intent find(final InstanceKey key) throws IndexOutOfBoundsException {
if (key == null) {