Build coarse Android Environment

Governed by AndroidEntryPointManager.setDoBootSequence generate some
coarse Android-environment before starting the LiveCycle-Model.

Some action is taken to attach the Android-Context to Components - much
is still missing there though.
Thin context is mainly useful when starting Intents of an external App.
This commit is contained in:
Tobias Blaschke 2014-02-02 21:53:45 +01:00 committed by Juergen Graf
parent 0543761699
commit 9c7a2eb975
4 changed files with 724 additions and 0 deletions

View File

@ -82,8 +82,10 @@ import com.ibm.wala.util.ssa.IInstantiator;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters.IInstantiationBehavior;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters.IInstantiationBehavior.InstanceBehavior;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.structure.AbstractAndroidModel;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidBoot;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs.AndroidStartComponentTool;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.dalvik.util.AndroidTypes;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentStarters;
@ -159,6 +161,11 @@ public class AndroidModel /* makes SummarizedMethod */
private IProgressMonitor monitor;
private int maxProgress;
/*
* static: "boot" only once. How to assert done by the right one?
*/
protected static boolean doBoot = true;
protected IClass klass;
protected boolean built;
@ -258,6 +265,8 @@ public class AndroidModel /* makes SummarizedMethod */
this.monitor = AndroidEntryPointManager.MANAGER.getProgressMonitor();
this.maxProgress = entrypoints.size();
this.doBoot &= AndroidEntryPointManager.MANAGER.getDoBootSequence();
// BUILD
this.monitor.beginTask("Building " + name, this.maxProgress);
populate(entrypoints);
@ -350,6 +359,52 @@ public class AndroidModel /* makes SummarizedMethod */
final TypeSafeInstructionFactory tsif = new TypeSafeInstructionFactory(this.cha);
final Instantiator instantiator = new Instantiator (this.body, tsif, this.paramManager, this.cha, this.mRef, this.scope);
//
// Add preparing code to the model
//
if (this.doBoot) {
final Set<Parameter> allActivities = new HashSet(modelAcc.allExtend(AndroidTypes.ActivityName, getClassHierarchy()));
//assert(allActivities.size() > 0) : "There are no Activities in the Model"; // XXX
final IntentStarters.StartInfo toolInfo = IntentStarters.StartInfo.makeContextFree(null);
final AndroidStartComponentTool tool = new AndroidStartComponentTool(this.cha, this.mRef, toolInfo.getFlags(),
/* caller */ null, tsif, modelAcc, this.paramManager, this.body, /* self */ null, toolInfo, /* callerNd */ null);
final SSAValue application;
{
final SSAValue tmpApp = modelAcc.firstExtends(AndroidTypes.ApplicationName, this.cha);
if (tmpApp != null) {
application = tmpApp;
} else {
// Generate a real one?
logger.warn("I didn't get an application");
application = paramManager.getUnmanaged(AndroidTypes.Application, "app");
this.body.addConstant(application.getNumber(), new ConstantValue(null));
application.setAssigned();
}
}
final SSAValue nullIntent;
{
nullIntent = paramManager.getUnmanaged(AndroidTypes.Intent, "nullIntent");
this.body.addConstant(nullIntent.getNumber(), new ConstantValue(null));
nullIntent.setAssigned();
}
final SSAValue nullBinder;
{
nullBinder = paramManager.getUnmanaged(AndroidTypes.IBinder, "nullBinder");
this.body.addConstant(nullBinder.getNumber(), new ConstantValue(null));
nullBinder.setAssigned();
}
logger.info("Adding Boot-Code to the Android model");
{
final AndroidBoot boot = new AndroidBoot(null);
boot.addBootCode(tsif, null, paramManager, this.body);
tool.attachActivities(allActivities, application, boot.getMainThread(), /* Should be application context TODO */
boot.getPackageContext(), nullBinder, nullIntent);
}
// TODO: Assign context to the other components
}
logger.info("Populating the AndroidModel with {} entryPoints", this.maxProgress);
@ -623,11 +678,19 @@ public class AndroidModel /* makes SummarizedMethod */
final AndroidStartComponentTool tool = new AndroidStartComponentTool(getClassHierarchy(), asMethod, flags, caller, instructionFactory,
acc, pm, redirect, self, info, callerNd);
final AndroidTypes.AndroidContextType contextType;
final SSAValue androidContext; // of AndroidTypes.Context: The callers android-context
androidContext = tool.fetchCallerContext();
contextType = tool.typeOfCallerContext();
try { // Add additional Info if Exception occurs...
// TODO: Check, that caller is an activity where necessary!
// TODO: Call Activity.setIntent
final SSAValue iBinder = tool.fetchIBinder(androidContext);
tool.assignIBinder(iBinder, allActivities);
// Call the model
{
@ -735,6 +798,8 @@ public class AndroidModel /* makes SummarizedMethod */
//final List<Parameter> modelsActivities = modelAcc.allExtend(AndroidTypes.ActivityName, getClassHierarchy()); // are in models scope
//final List<SSAValue> allActivities = new ArrayList<SSAValue>(modelsActivities.size()); // create instances in this scope
System.err.println("\tcontextType=\t" + contextType);
System.err.println("\tandroidContetx=\t" + androidContext);
System.err.println("\tasMethod=\t" + asMethod);
System.err.println("\tcaller=\t" + caller);
System.err.println("\tinfo=\t" + info);

View File

@ -0,0 +1,350 @@
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.ibm.wala.dalvik.ipa.callgraph.androidModel.stubs;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.Selector;
import com.ibm.wala.dalvik.util.AndroidTypes;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
import com.ibm.wala.util.ssa.ParameterAccessor;
import com.ibm.wala.util.ssa.SSAValue;
import com.ibm.wala.ipa.summaries.VolatileMethodSummary;
import com.ibm.wala.util.ssa.SSAValueManager;
import java.util.Set;
import java.util.EnumSet;
import java.util.List;
import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Create some Android-Environment.
*
* Used by the AndroidModel to assign some fields in the analyzed Application if the
* settings instruct it to do so.
*
* @see com.ibm.wala.dalvik.ipa.callgraph.androidModel.AndroidModel
* @see com.ibm.wala.dalvik.util.AndroidEntryPointManager
*
* @author Tobias Blaschke <code@tobiasblaschke.de>
* @since 2013-10-23
*/
public class AndroidBoot {
private static Logger logger = LoggerFactory.getLogger(AndroidBoot.class);
public static enum BootAction {
/**
* Create an instance of android.app.ContextImpl for the system.
*/
CREATE_SYSTEM_CONTEXT,
/**
* Crate an instance of android.app.ContextImpl for the apk.
*/
CREATE_APK_CONTEXT,
}
//public static Set<BootAction> BOOT_ALL = EnumSet.allOf(BootAction);
private final MethodReference scope;
private TypeSafeInstructionFactory instructionFactory;
private ParameterAccessor acc;
private SSAValueManager pm;
private VolatileMethodSummary body;
public AndroidBoot(Set<BootAction> whatToDo) {
this.scope = null; // Place something here?
}
private SSAValue mainThread = null;
private SSAValue systemContext = null;
private SSAValue packageContext = null;
public void addBootCode(final TypeSafeInstructionFactory instructionFactory, final ParameterAccessor acc,
final SSAValueManager pm, final VolatileMethodSummary body) {
this.instructionFactory = instructionFactory;
this.acc = acc;
this.pm = pm;
this.body = body;
mainThread = createMainThred();
systemContext = createSystemContext(mainThread);
packageContext = createPackageContext(mainThread, systemContext);
}
public SSAValue getSystemContext() {
if (systemContext == null) {
throw new IllegalStateException("No value for systemContext - was addBootCode called?");
}
return systemContext;
}
public SSAValue getPackageContext() {
if (packageContext == null) {
throw new IllegalStateException("No value for packageContext - was addBootCode called?");
}
return packageContext;
}
public SSAValue getMainThread() {
if (mainThread == null) {
throw new IllegalStateException("No value for mainThread - was addBootCode called?");
}
return mainThread;
}
/**
* Create the main-thread as activity-thread.
*/
private SSAValue createMainThred() {
final SSAValue mainThread = this.pm.getUnmanaged(AndroidTypes.ActivityThread, "mMainThred");
{ // New-Site
final int pc = this.body.getNextProgramCounter();
final NewSiteReference nRef = NewSiteReference.make(pc, AndroidTypes.ActivityThread);
final SSAInstruction newInstr = this.instructionFactory.NewInstruction(pc, mainThread, nRef);
body.addStatement(newInstr);
}
/*{ // clinit
final int pc = this.body.getNextProgramCounter();
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ActivityThread, MethodReference.clinitSelector);
final SSAValue exception = new SSAValue(this.pm.getUnmanaged(), TypeReference.JavaLangException, this.scope, "ctor_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.SPECIAL);
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(mainThread);
final SSAInstruction ctorCall = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(ctorCall);
}*/
{ // CTor-Call
final int pc = this.body.getNextProgramCounter();
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ActivityThread, MethodReference.initSelector);
final SSAValue exception = this.pm.getUnmanaged(TypeReference.JavaLangException, "ctor_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.SPECIAL);
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(mainThread);
final SSAInstruction ctorCall = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(ctorCall);
}
return mainThread;
}
/**
* Create an instance of android.app.ContextImpl for the system.
*
* @see android.app.ContextImpl.createPackageContextAsUser
*/
private SSAValue createSystemContext(SSAValue mainThread) {
final SSAValue systemContext = this.pm.getUnmanaged(AndroidTypes.ContextImpl, "systemContextImpl");
{ // Call ContextImpl.getSystemContext()
final int pc = this.body.getNextProgramCounter();
final Descriptor desc = Descriptor.findOrCreate(new TypeName[0], AndroidTypes.ContextImplName);
final Selector mSel = new Selector(Atom.findOrCreateAsciiAtom("getSystemContext"), desc);
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ActivityThread, mSel);
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final SSAValue exception = this.pm.getException();
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(mainThread);
final SSAInstruction call = instructionFactory.InvokeInstruction(pc, systemContext, params, exception, site);
body.addStatement(call);
}
{ // putting mRestricted = false
final SSAValue falseConst = this.pm.getUnmanaged(TypeReference.Boolean, "falseConst");
this.body.addConstant(falseConst.getNumber(), new ConstantValue(false));
falseConst.setAssigned();
final int pc = this.body.getNextProgramCounter();
final FieldReference mRestricted = FieldReference.findOrCreate(AndroidTypes.ContextImpl, Atom.findOrCreateAsciiAtom("mRestricted"),
TypeReference.Boolean);
final SSAInstruction putInst = instructionFactory.PutInstruction(pc, systemContext, falseConst, mRestricted);
body.addStatement(putInst);
}
return systemContext;
}
/**
* Create an instance of android.app.ContextImpl for the apk.
*
* @see android.app.ContextImpl.createPackageContextAsUser
*/
private SSAValue createPackageContext(final SSAValue mainThread, final SSAValue systemContext) {
final SSAValue packageContext = this.pm.getUnmanaged(AndroidTypes.ContextImpl, "packageContextImpl");
{ // New-Site
final int pc = this.body.getNextProgramCounter();
final NewSiteReference nRef = NewSiteReference.make(pc, AndroidTypes.ContextImpl);
final SSAInstruction newInstr = this.instructionFactory.NewInstruction(pc, packageContext, nRef);
body.addStatement(newInstr);
}
/*{ // clnint
final int pc = this.body.getNextProgramCounter();
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ContextImpl, MethodReference.clinitSelector);
final SSAValue exception = new SSAValue(this.pm.getUnmanaged(), TypeReference.JavaLangException, this.scope, "ctor_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.SPECIAL);
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(packageContext);
final SSAInstruction ctorCall = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(ctorCall);
}*/
{ // CTor-Call
final int pc = this.body.getNextProgramCounter();
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ContextImpl, MethodReference.initSelector);
final SSAValue exception = this.pm.getUnmanaged(TypeReference.JavaLangException, "ctor_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.SPECIAL);
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(packageContext);
final SSAInstruction ctorCall = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(ctorCall);
}
{ // putting mRestricted = false
final SSAValue falseConst = this.pm.getUnmanaged(TypeReference.Boolean, "falseConst");
this.body.addConstant(falseConst.getNumber(), new ConstantValue(false));
falseConst.setAssigned();
final int pc = this.body.getNextProgramCounter();
final FieldReference mRestricted = FieldReference.findOrCreate(AndroidTypes.ContextImpl, Atom.findOrCreateAsciiAtom("mRestricted"),
TypeReference.Boolean);
final SSAInstruction putInst = instructionFactory.PutInstruction(pc, packageContext, falseConst, mRestricted);
body.addStatement(putInst);
}
final SSAValue packageName;
{ // Generating pacakge name
packageName = this.pm.getUnmanaged(TypeReference.JavaLangString, "packageName");
this.body.addConstant(packageName.getNumber(), new ConstantValue("foo")); // TODO: Fetch name
packageName.setAssigned();
}
final SSAValue uid = this.pm.getUnmanaged(AndroidTypes.UserHandle, "uid");
{ // New UserHandle
final int pc = this.body.getNextProgramCounter();
final NewSiteReference nRef = NewSiteReference.make(pc, AndroidTypes.UserHandle);
final SSAInstruction newInstr = this.instructionFactory.NewInstruction(pc, uid, nRef);
body.addStatement(newInstr);
}
/*{ // UserHandle(1000) // TODO: seems android-subs do not contain this
final SSAValue nrUid = new SSAValue(this.pm.getUnmanaged(), TypeReference.Int, this.scope, "nrUid");
this.body.addConstant(nrUid.getNumber(), new ConstantValue(1000)); // First regular linux user
nrUid.setAssigned();
final int pc = this.body.getNextProgramCounter();
final Descriptor descr = Descriptor.findOrCreate(new TypeName[] { TypeReference.IntName }, TypeReference.VoidName);
final Selector mSel = new Selector(MethodReference.initAtom, descr);
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.UserHandle, mSel);
final SSAValue exception = new SSAValue(this.pm.getUnmanaged(), TypeReference.JavaLangException, this.scope, "ctor_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.SPECIAL);
final List<SSAValue> params = new ArrayList<SSAValue>(2);
params.add(uid);
params.add(nrUid);
final SSAInstruction ctorCall = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(ctorCall);
} // */
/*{ // packageContext.init(pi = null, null, mMainThread, mResources = null, mBasePackageName, user); TODO: Not in android stubs
final SSAValue nullApk = new SSAValue(this.pm.getUnmanaged(), AndroidTypes.LoadedApk, this.scope, "nullApk"); // TODO
this.body.addConstant(nullApk.getNumber(), new ConstantValue(null));
nullApk.setAssigned();
final SSAValue nullIBinder = new SSAValue(this.pm.getUnmanaged(), AndroidTypes.IBinder, this.scope, "nullBinder");
this.body.addConstant(nullIBinder.getNumber(), new ConstantValue(null));
nullIBinder.setAssigned();
final SSAValue nullResources = new SSAValue(this.pm.getUnmanaged(), AndroidTypes.Resources, this.scope, "nullResources"); // TODO
this.body.addConstant(nullResources.getNumber(), new ConstantValue(null));
nullResources.setAssigned();
final int pc = this.body.getNextProgramCounter();
final Descriptor desc = Descriptor.findOrCreate(new TypeName[] {
AndroidTypes.LoadedApkName,
AndroidTypes.IBinderName,
AndroidTypes.ActivityThreadName,
AndroidTypes.ResourcesName,
TypeName.string2TypeName("Ljava/lang/String"), // Private?! TypeReference.JavaLangStringName,
AndroidTypes.UserHandleName}, TypeReference.VoidName);
final Selector mSel = new Selector(Atom.findOrCreateAsciiAtom("init"), desc); // the name of the function is actually init
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ContextImpl, mSel);
final SSAValue exception = new SSAValue(this.pm.getUnmanaged(), TypeReference.JavaLangException, this.scope, "init_exc" );
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final List<SSAValue> params = new ArrayList<SSAValue>(7);
params.add(packageContext);
params.add(nullApk); // TODO: This would contain a Context too?
params.add(nullIBinder); // OK: is null in Android-Sources too
params.add(mainThread);
params.add(nullResources); // TODO
params.add(packageName);
params.add(uid);
final SSAInstruction call = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(call);
} // */
{ // XXX: ALTERNATIVE FROM THE ABOVE, THAT IS IN STUBS!!
// init(Landroid/app/LoadedApk;Landroid/os/IBinder;Landroid/app/ActivityThread;)V
final SSAValue nullApk = this.pm.getUnmanaged(AndroidTypes.LoadedApk, "nullApk"); // TODO
this.body.addConstant(nullApk.getNumber(), new ConstantValue(null));
nullApk.setAssigned();
final SSAValue nullIBinder = this.pm.getUnmanaged(AndroidTypes.IBinder, "nullBinder");
this.body.addConstant(nullIBinder.getNumber(), new ConstantValue(null));
nullIBinder.setAssigned();
final int pc = this.body.getNextProgramCounter();
final Descriptor desc = Descriptor.findOrCreate(new TypeName[] {
AndroidTypes.LoadedApkName,
AndroidTypes.IBinderName,
AndroidTypes.ActivityThreadName,
}, TypeReference.VoidName);
final Selector mSel = new Selector(Atom.findOrCreateAsciiAtom("init"), desc); // the name of the function is actually init
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ContextImpl, mSel);
final SSAValue exception = this.pm.getException();
final CallSiteReference site = CallSiteReference.make(pc, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final List<SSAValue> params = new ArrayList<SSAValue>(7);
params.add(packageContext);
params.add(nullApk); // TODO: This would contain a Context too?
params.add(nullIBinder); // OK: is null in Android-Sources too
params.add(mainThread);
final SSAInstruction call = instructionFactory.InvokeInstruction(pc, params, exception, site);
body.addStatement(call);
}
return packageContext;
}
private SSAValue createApplicationContext(final SSAValue mainThread, final SSAValue systemContext) {
return null; // TODO
}
}

View File

@ -147,6 +147,290 @@ public class AndroidStartComponentTool {
this.callerNd = callerNd;
}
public void attachActivities(Set<? extends SSAValue> activities, SSAValue application, SSAValue thread, SSAValue context,
SSAValue iBinderToken, SSAValue intent) {
// call: final void Activity.attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
// Application application, Intent intent, ActivityInfo info, CharSequence title,
// Activity parent, String id, Object lastNonConfigurationInstance,
// Configuration config)
final SSAValue nullInstrumentation;
{
nullInstrumentation = pm.getUnmanaged(AndroidTypes.Instrumentation, "nullInstrumentation");
this.redirect.addConstant(nullInstrumentation.getNumber(), new ConstantValue(null));
nullInstrumentation.setAssigned();
}
final SSAValue nullInfo;
{
nullInfo = pm.getUnmanaged(AndroidTypes.ActivityInfo, "nullInfo");
this.redirect.addConstant(nullInfo.getNumber(), new ConstantValue(null));
nullInfo.setAssigned();
}
final SSAValue title;
{
title = pm.getUnmanaged(TypeReference.JavaLangString, "title"); // XXX CharSequence
this.redirect.addConstant(title.getNumber(), new ConstantValue("title"));
title.setAssigned();
}
final SSAValue nullParent;
{
nullParent = pm.getUnmanaged(AndroidTypes.Activity, "nullParent");
this.redirect.addConstant(nullParent.getNumber(), new ConstantValue(null));
nullParent.setAssigned();
}
final SSAValue nullConfigInstance;
{
final TypeName cName = TypeName.string2TypeName("Landroid/app/Activity$NonConfigurationInstances");
final TypeReference type = TypeReference.findOrCreate(com.ibm.wala.types.ClassLoaderReference.Primordial, cName);
nullConfigInstance = pm.getUnmanaged(type, "noState");
this.redirect.addConstant(nullConfigInstance.getNumber(), new ConstantValue(null));
nullConfigInstance.setAssigned();
}
final SSAValue nullConfiguration;
{
nullConfiguration = pm.getUnmanaged(AndroidTypes.Configuration, "nullConfig");
this.redirect.addConstant(nullConfiguration.getNumber(), new ConstantValue(null));
nullConfiguration.setAssigned();
}
final Descriptor desc = Descriptor.findOrCreate(new TypeName[] {
AndroidTypes.ContextName,
AndroidTypes.ActivityThreadName,
AndroidTypes.InstrumentationName,
AndroidTypes.IBinderName,
AndroidTypes.ApplicationName,
AndroidTypes.IntentName,
AndroidTypes.ActivityInfoName,
TypeName.string2TypeName("Ljava/lang/CharSequence"),
AndroidTypes.ActivityName,
TypeReference.JavaLangString.getName(),
TypeName.string2TypeName("Landroid/app/Activity$NonConfigurationInstances"),
AndroidTypes.ConfigurationName }, TypeReference.VoidName);
final Selector mSel = new Selector(Atom.findOrCreateAsciiAtom("attach"), desc);
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.Activity, mSel);
final List<SSAValue> params = new ArrayList<SSAValue>(13);
params.add(null); // activity
params.add(context);
params.add(thread);
params.add(nullInstrumentation);
params.add(iBinderToken);
params.add(application);
params.add(intent);
params.add(nullInfo);
params.add(title);
params.add(nullParent);
params.add(title);
params.add(nullConfigInstance);
params.add(nullConfiguration);
for (final SSAValue activity: activities) {
final int callPC = redirect.getNextProgramCounter();
final CallSiteReference site = CallSiteReference.make(callPC, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final SSAValue exception = pm.getException();
params.set(0, activity);
final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, params, exception, site);
redirect.addStatement(invokation);
}
}
public AndroidTypes.AndroidContextType typeOfCallerContext() {
return this.callerContext;
}
/**
* Fetches the context of the caller.
*
* @return A new SSAValue representing the androidContext (may be null!). // XXX
*/
public SSAValue fetchCallerContext() {
/*if (flags.contains(StarterFlags.CONTEXT_FREE)) {
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.getName().equals(AndroidTypes.ContextWrapperName)) {
{ // Fetch ContextWrapperName.mBase => androidContext
androidContext = pm.getUnmanaged(AndroidTypes.Context, "callerContext");
logger.debug("Fetching ContextWrapperName.mBase");
final FieldReference mBaseRef = FieldReference.findOrCreate(AndroidTypes.ContextWrapper, Atom.findOrCreateAsciiAtom("mBase"),
AndroidTypes.Context);
final int instPC = redirect.getNextProgramCounter();
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, androidContext, self, mBaseRef);
redirect.addStatement(getInst);
// TODO: somehow dispatch on type of mBase?
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;
this.callerContext = AndroidTypes.AndroidContextType.CONTEXT_IMPL;
logger.info("Caller has android-context type: ContextImpl");
return androidContext;
}
} else if (caller.getName().equals(AndroidTypes.ActivityName)) {
// We don't need it for now - TODO grab anyway
androidContext = null;
this.callerContext = AndroidTypes.AndroidContextType.ACTIVITY;
logger.info("Caller has android-context type: Activity");
return androidContext;
} else if (caller.equals(AndroidModelClass.ANDROID_MODEL_CLASS)) {
// TODO: Return something useful
this.callerContext = AndroidTypes.AndroidContextType.USELESS;
return null;
} else if (caller.getName().equals(AndroidTypes.BridgeContextName)) {
// XXX ???
androidContext = self;
this.callerContext = AndroidTypes.AndroidContextType.CONTEXT_BRIDGE;
logger.info("Caller has android-context type: BridgeContext");
return androidContext;
} else {
throw new UnsupportedOperationException("Can not handle the callers android-context of " + caller);
}
}
/**
* Fetch the permissions to start the component with.
*
* Fetching depends on StarterFlags.QUENCH_PERMISSIONS, XXX
*
* @return an iBinder
* @throws UnsupportedOperationException when fetching is not supported with the current settings
*/
public SSAValue fetchIBinder(SSAValue androidContext) {
logger.debug("Fetching context to use for call...");
final SSAValue iBinder = pm.getUnmanaged(AndroidTypes.IBinder, "foreignIBinder");
if (flags.contains(StarterFlags.CONTEXT_FREE)) {
// TODO: Can we do somethig?
return null;
} else if (flags.contains(StarterFlags.QUENCH_PERMISSIONS)) {
// If this flag is set the given asMethod has a IntentSender-Parameter
final Parameter intentSender = acc.firstOf(AndroidTypes.IntentSenderName);
assert (intentSender != null) : "Unable to look up the IntentSender-Object";
assert (intentSender.getNumber() == 2) : "The IntentSender-Object was not located at SSA-Number 2. This may be entirely " +
"ok! I left this assertion to ashure the ParameterAccessor does its job right.";
// retreive the IBinder: IIntentSender.asBinder()
final SSAValue iIntentSender = pm.getUnmanaged(AndroidTypes.IIntentSender, "iIntentSender");
{ // call IIntentSender IntentSender.getTarget()
final int callPC = redirect.getNextProgramCounter();
final Selector mSel = Selector.make("getTarget()Landroid/content/IIntentSender;");
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.IntentSender, mSel);
final CallSiteReference site = CallSiteReference.make(callPC, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final SSAValue exception = pm.getException();
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(intentSender);
final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, iIntentSender, params, exception, site);
redirect.addStatement(invokation);
}
{ // call IBinder IIntentSender.asBinder()
final int callPC = redirect.getNextProgramCounter();
final Selector mSel = Selector.make("asBinder()Landroid/os/IBinder;");
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.IntentSender, mSel);
final CallSiteReference site = CallSiteReference.make(callPC, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final SSAValue exception = pm.getException();
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(iIntentSender);
final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, iBinder, params, exception, site);
redirect.addStatement(invokation);
}
logger.info("The context to use for the call is from an IBinder");
return iBinder;
} else if (caller.getName().equals(AndroidTypes.ActivityName)) {
// The IBinder is Activity.mMainThread.getApplicationThread() // TODO: Verify
final SSAValue mMainThread = pm.getUnmanaged(AndroidTypes.ActivityThread, "callersMainThred");
{ // Fetch mMainthred
final int instPC = redirect.getNextProgramCounter();
final FieldReference mMainThreadRef = FieldReference.findOrCreate(AndroidTypes.Activity, Atom.findOrCreateAsciiAtom("mMainThread"),
AndroidTypes.ActivityThread);
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, mMainThread, self, mMainThreadRef);
redirect.addStatement(getInst);
}
/*{ // DEBUG
final com.ibm.wala.classLoader.IClass activityThread = cha.lookupClass(AndroidTypes.ActivityThread);
assert (activityThread != null);
for (com.ibm.wala.classLoader.IMethod m : activityThread.getDeclaredMethods()) {
System.out.println(m);
}
} // */
{ // Call getApplicationThread() on it
final int callPC = redirect.getNextProgramCounter();
final Selector mSel = Selector.make("getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;");
final MethodReference mRef = MethodReference.findOrCreate(AndroidTypes.ActivityThread, mSel);
final CallSiteReference site = CallSiteReference.make(callPC, mRef, IInvokeInstruction.Dispatch.VIRTUAL);
final SSAValue exception = pm.getException();
final List<SSAValue> params = new ArrayList<SSAValue>(1);
params.add(mMainThread);
final SSAInstruction invokation = instructionFactory.InvokeInstruction(callPC, iBinder, params, exception, site);
redirect.addStatement(invokation);
} // */
logger.info("The context (IBinder) to use for the call is the one from the calling activity");
return iBinder;
} else if (this.callerContext == AndroidTypes.AndroidContextType.CONTEXT_IMPL) {
// For bindService its mActivityToken - TODO: For the rest?
// startActivity uses mMainThread.getApplicationThread()
{ // read mActivityToken -> iBinder
logger.debug("Fetching ContextImpl.mActivityToken to iBinder");
final FieldReference mActivityTokenRef = FieldReference.findOrCreate(AndroidTypes.ContextImpl,
Atom.findOrCreateAsciiAtom("mActivityToken"), AndroidTypes.IBinder);
final int instPC = redirect.getNextProgramCounter();
final SSAInstruction getInst = instructionFactory.GetInstruction(instPC, iBinder, androidContext, mActivityTokenRef);
redirect.addStatement(getInst);
}
logger.info("The context (IBinder) to use for the call is the one from the caller");
return iBinder;
} else if (this.callerContext == AndroidTypes.AndroidContextType.CONTEXT_BRIDGE) {
// TODO: Return something useful
logger.error("Not Implemented: Fetch an IBinder from a BridgeContext.");
return null;
} else if (caller.equals(AndroidModelClass.ANDROID_MODEL_CLASS)) {
// TODO: Return something useful
return null;
} else {
throw new UnsupportedOperationException("No implementation on how to extract an iBinder from a " + caller);
}
}
/**
* Set the iBinder in the callee.
*/
public void assignIBinder(SSAValue iBinder, List<? extends SSAValue> allActivities) {
if (iBinder == null) {
// TODO: Some day we may throe here...
return;
}
logger.info("Assigning the iBinder");
// TODO: Use Phi?
for (SSAValue activity : allActivities) {
logger.debug("\tto: {}", activity);
//final int callPC = redirect.getNextProgramCounter();
final FieldReference mTokenRef = FieldReference.findOrCreate(AndroidTypes.Activity, Atom.findOrCreateAsciiAtom("mToken"),
AndroidTypes.IBinder);
final int instPC = redirect.getNextProgramCounter();
final SSAInstruction putInst = instructionFactory.PutInstruction(instPC, activity, iBinder, mTokenRef);
redirect.addStatement(putInst);
}
}
/**
* Grab mResultCode and mResultData.

View File

@ -157,6 +157,31 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return prev;
}
private boolean doBootSequence = true;
/**
* Whether to generate a global android environment.
*
* It's possible to analyze android-applications without creating these structures and save
* some memory. In this case some calls to the OS (like getting the Activity-manager or so)
* will not be able to be resolved.
*/
public boolean getDoBootSequence() {
return this.doBootSequence;
}
/**
* Whether to generate a global android environment.
*
* See the {@link #getDoBootSequence()} documentation.
*
* @return the previous setting of doBootSequence
*/
public boolean setDoBootSequence(boolean doBootSequence) {
boolean prev = this.doBootSequence;
this.doBootSequence = doBootSequence;
return prev;
}
private Class abstractAndroidModel = LoopAndroidModel.class;
/**
* What special handling to insert into the model.