org.scandroid.util.AndroidAnalysisContext Maven / Gradle / Ivy
Show all versions of com.ibm.wala.scandroid Show documentation
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2009-2012,
*
* Adam Fuchs Avik Chaudhuri Steve Suh
* Galois, Inc. (Adam Foltzer 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 org.scandroid.util;
import com.google.common.collect.Queues;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.core.util.io.FileProvider;
import com.ibm.wala.core.util.strings.Atom;
import com.ibm.wala.core.util.warnings.Warnings;
import com.ibm.wala.dalvik.util.AndroidAnalysisScope;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.ClassTargetSelector;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXCFABuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.summaries.BypassClassTargetSelector;
import com.ibm.wala.ipa.summaries.BypassMethodTargetSelector;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Deque;
import java.util.Map;
import java.util.Set;
public class AndroidAnalysisContext {
private static final String methodSpec = "MethodSummaries.xml";
private static final String pathToSpec = "data";
private final ISCanDroidOptions options;
private final AnalysisScope scope;
private final ClassHierarchy cha;
public AndroidAnalysisContext() {
throw new IllegalArgumentException();
}
public AndroidAnalysisContext(ISCanDroidOptions options)
throws IllegalArgumentException, ClassHierarchyException, IOException {
this(options, "Java60RegressionExclusions.txt");
}
public AndroidAnalysisContext(ISCanDroidOptions options, String exclusions)
throws IOException, IllegalArgumentException, ClassHierarchyException {
this.options = options;
scope =
AndroidAnalysisScope.setUpAndroidAnalysisScope(
options.getClasspath(),
exclusions,
getClass().getClassLoader(),
options.getAndroidLibrary());
cha = ClassHierarchyFactory.make(scope);
/*
if (options.classHierarchyWarnings()) {
// log ClassHierarchy warnings
for (Warning w : Iterator2Iterable.make(Warnings.iterator())) {
}
}
*/
Warnings.clear();
}
public static SSAPropagationCallGraphBuilder makeVanillaZeroOneCFABuilder(
AnalysisOptions options,
IAnalysisCacheView cache,
IClassHierarchy cha,
AnalysisScope scope,
ContextSelector customSelector,
SSAContextInterpreter customInterpreter,
InputStream summariesStream,
MethodSummary extraSummary) {
if (options == null) {
throw new IllegalArgumentException("options is null");
}
Util.addDefaultSelectors(options, cha);
// addDefaultBypassLogic(options, scope, Util.class.getClassLoader(),
// cha);
// addBypassLogic(options, scope,
// AndroidAppLoader.class.getClassLoader(), methodSpec, cha);
addBypassLogic(options, scope, summariesStream, cha, extraSummary);
return ZeroXCFABuilder.make(
Language.JAVA,
cha,
options,
cache,
customSelector,
customInterpreter,
ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.CONSTANT_SPECIFIC);
}
/**
* @param options options that govern call graph construction
* @param cha governing class hierarchy
* @param scope representation of the analysis scope
* @param customSelector user-defined context selector, or null if none
* @param customInterpreter user-defined context interpreter, or null if none
* @return a 0-CFA Call Graph Builder.
* @throws IllegalArgumentException if options is null
*
TODO: move
*/
public static SSAPropagationCallGraphBuilder makeZeroCFABuilder(
AnalysisOptions options,
IAnalysisCacheView cache,
IClassHierarchy cha,
AnalysisScope scope,
ContextSelector customSelector,
SSAContextInterpreter customInterpreter,
Collection summariesStreams,
MethodSummary extraSummary) {
if (options == null) {
throw new IllegalArgumentException("options is null");
}
Util.addDefaultSelectors(options, cha);
for (InputStream stream : summariesStreams) {
addBypassLogic(options, scope, stream, cha, extraSummary);
}
return ZeroXCFABuilder.make(
Language.JAVA,
cha,
options,
cache,
customSelector,
customInterpreter,
ZeroXInstanceKeys.NONE);
}
// public static void addBypassLogic(AnalysisOptions options, AnalysisScope
// scope, ClassLoader cl, String xmlFile,
// IClassHierarchy cha) throws IllegalArgumentException {
public static void addBypassLogic(
AnalysisOptions options,
AnalysisScope scope,
InputStream xmlIStream,
IClassHierarchy cha,
MethodSummary extraSummary)
throws IllegalArgumentException {
if (scope == null) {
throw new IllegalArgumentException("scope is null");
}
if (options == null) {
throw new IllegalArgumentException("options is null");
}
// if (cl == null) {
// throw new IllegalArgumentException("cl is null");
// }
if (cha == null) {
throw new IllegalArgumentException("cha cannot be null");
}
try {
Set summaryClasses = HashSetFactory.make();
Map summaries = HashMapFactory.make();
if (null != xmlIStream) {
XMLMethodSummaryReader newSummaryXML = loadMethodSummaries(scope, xmlIStream);
summaryClasses.addAll(newSummaryXML.getAllocatableClasses());
summaries.putAll(newSummaryXML.getSummaries());
}
// for (MethodReference mr : summaries.keySet()) {
//
// }
try (final InputStream s =
new FileProvider()
.getInputStreamFromClassLoader(
pathToSpec + File.separator + methodSpec,
AndroidAnalysisContext.class.getClassLoader())) {
XMLMethodSummaryReader nativeSummaries = loadMethodSummaries(scope, s);
summaries.putAll(nativeSummaries.getSummaries());
summaryClasses.addAll(nativeSummaries.getAllocatableClasses());
if (extraSummary != null) {
summaries.put(extraSummary.getMethod(), extraSummary);
}
MethodTargetSelector ms =
new BypassMethodTargetSelector(
options.getMethodTargetSelector(), summaries,
nativeSummaries.getIgnoredPackages(), cha);
options.setSelector(ms);
ClassTargetSelector cs =
new BypassClassTargetSelector(
options.getClassTargetSelector(),
summaryClasses,
cha,
cha.getLoader(scope.getLoader(Atom.findOrCreateUnicodeAtom("Synthetic"))));
options.setSelector(cs);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static XMLMethodSummaryReader loadMethodSummaries(
AnalysisScope scope, InputStream xmlIStream) {
try (@SuppressWarnings("resource")
InputStream s =
xmlIStream != null
? xmlIStream
: AndroidAnalysisContext.class
.getClassLoader()
.getResourceAsStream(pathToSpec + File.separator + methodSpec)) {
return new XMLMethodSummaryReader(s, scope);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/** Returns all concrete classes implementing the given interface or any subinterfaces */
public Collection concreteClassesForInterface(IClass iRoot) {
Set clazzes = HashSetFactory.make();
Set done = HashSetFactory.make();
Deque todo = Queues.newArrayDeque();
todo.push(iRoot);
while (!todo.isEmpty()) {
IClass i = todo.pop();
for (IClass clazz : cha.getImplementors(i.getReference())) {
if (clazz.isInterface() && !done.contains(clazz)) {
done.add(i);
todo.push(clazz);
} else if (!clazz.isAbstract()) {
clazzes.add(clazz);
}
}
}
return clazzes;
}
public ISCanDroidOptions getOptions() {
return options;
}
public AnalysisScope getScope() {
return scope;
}
public ClassHierarchy getClassHierarchy() {
return cha;
}
}