kr.ac.kaist.wala.hybridroid.callgraph.AndroidHybridAnalysisScope.java Source code

Java tutorial

Introduction

Here is the source code for kr.ac.kaist.wala.hybridroid.callgraph.AndroidHybridAnalysisScope.java

Source

/*******************************************************************************
* Copyright (c) 2016 IBM Corporation and KAIST.
* All rights reserved. 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
*
* Contributors:
* KAIST - initial API and implementation
*******************************************************************************/
package kr.ac.kaist.wala.hybridroid.callgraph;

import com.ibm.wala.cast.ir.translator.TranslatorToCAst.Error;
import com.ibm.wala.cast.js.html.DefaultSourceExtractor;
import com.ibm.wala.cast.js.html.WebUtil;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.classLoader.SourceModule;
import com.ibm.wala.classLoader.SourceURLModule;
import com.ibm.wala.dalvik.classLoader.DexFileModule;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.config.FileOfClasses;
import com.ibm.wala.util.strings.Atom;
import kr.ac.kaist.wala.hybridroid.models.AndroidHybridAppModel;
import kr.ac.kaist.wala.hybridroid.util.file.FileWriter;
import org.apache.commons.lang3.SystemUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;

/**
 * AnalysisScope for Android Hybrid application. This class supports DROIDEL Dex
 * scope or original Android platform scope as well as JavaScript scope.
 * 
 * @author Sungho Lee
 */

public class AndroidHybridAnalysisScope extends AnalysisScope {

    public static boolean DEBUG = false;

    private static final Set<Language> languages;

    static {
        languages = HashSetFactory.make();

        languages.add(Language.JAVA);
        languages.add(JavaScriptLoader.JS);
    }

    public AndroidHybridAnalysisScope() {
        super(languages);
        this.initForJava();
        jsLoaderMap = new HashMap<Atom, ClassLoaderReference>();
        ClassLoaderReference jsLoader = JavaScriptTypes.jsLoader;
        loadersByName.put(JavaScriptTypes.jsLoaderName, jsLoader);
    }

    /**
     * Make AnalysisScope for Android hybrid application. If you want to use
     * DROIDEL as front-end, use setUpDroidelAnalysisScope method instead of
     * this.
     * 
     * @param classpath
     *            the target apk file uri.
     * @param htmls
     *            JavaScript files contained in the scope.
     * @param exclusions
     *            the exclusion file.
     * @param androidLib
     *            the Android framework directory uri.
     * @return AnalysisScope for Android hybrid application.
     * @throws IOException
     */
    public static AndroidHybridAnalysisScope setUpAndroidHybridAnalysisScope(String dir, URI classpath,
            Set<URL> htmls, String exclusions, URI... androidLib) throws IOException {
        AndroidHybridAnalysisScope scope;

        scope = new AndroidHybridAnalysisScope();

        File exclusionsFile = new File(exclusions);
        InputStream fs = exclusionsFile.exists() ? new FileInputStream(exclusionsFile)
                : AndroidHybridAppModel.class.getResourceAsStream(exclusions);
        scope.setExclusions(new FileOfClasses(fs));

        scope.setLoaderImpl(ClassLoaderReference.Primordial, "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl");

        for (URI al : androidLib) {
            if (al.getPath().endsWith(".dex"))
                scope.addToScope(ClassLoaderReference.Primordial, DexFileModule.make(new File(al)));
            else if (al.getPath().endsWith(".jar"))
                scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(new JarFile(new File(al))));
            else
                throw new InternalError("Android library must be either dex or jar file: " + al.getPath());
        }

        scope.setLoaderImpl(ClassLoaderReference.Application,
                "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl");

        scope.addToScope(ClassLoaderReference.Application, DexFileModule.make(new File(classpath)));

        if (!htmls.isEmpty())
            scope = setUpJsAnalysisScope(dir, scope, htmls);

        fs.close();

        return scope;
    }

    private static Map<Atom, Atom> nameConvertMap = new HashMap<Atom, Atom>();

    private static AndroidHybridAnalysisScope setUpJsAnalysisScope(String dir, AndroidHybridAnalysisScope scope,
            Set<URL> htmls) throws IllegalArgumentException, IOException {

        JavaScriptLoader.addBootstrapFile(WebUtil.preamble);
        if (SystemUtils.IS_OS_WINDOWS) {
            scope.addToScope(scope.getJavaScriptLoader(),
                    new SourceURLModule(AndroidHybridAppModel.class.getResource("prologue.js")) {
                        @Override
                        public String getName() {
                            return "prologue.js";
                        }
                    });
            scope.addToScope(scope.getJavaScriptLoader(),
                    new SourceURLModule(AndroidHybridAppModel.class.getResource("preamble.js")) {
                        @Override
                        public String getName() {
                            return "preamble.js";
                        }
                    });
        } else {
            scope.addToScope(scope.getJavaScriptLoader(),
                    new SourceURLModule(AndroidHybridAppModel.class.getResource("prologue.js")) {
                        @Override
                        public String getName() {
                            return "prologue.js";
                        }
                    });
            scope.addToScope(scope.getJavaScriptLoader(),
                    new SourceURLModule(AndroidHybridAppModel.class.getResource("preamble.js")) {
                        @Override
                        public String getName() {
                            return "preamble.js";
                        }
                    });
            //scope.addToScope(scope.getJavaScriptLoader(), JSCallGraphBuilderUtil.getPrologueFile("prologue.js"));
            //scope.addToScope(scope.getJavaScriptLoader(), JSCallGraphBuilderUtil.getPrologueFile("preamble.js"));
        }
        for (URL url : htmls) {
            try {
                File f = WebUtil.extractScriptFromHTML(url, DefaultSourceExtractor.factory).snd;
                scope.addToScope(scope.getJavaScriptLoader(), new SourceURLModule(f.toURI().toURL()));

                String jspath = f.getCanonicalPath();
                addScopeMap(Atom.findOrCreateAsciiAtom(url.toString()), Atom.findOrCreateAsciiAtom(
                        jspath.substring(jspath.lastIndexOf(File.separator) + 1, jspath.length())));
                if (DEBUG)
                    System.err.println("#Loaded html: " + url.getFile());
            } catch (Error | RuntimeException e) {// | UnimplementedError |
                // Error e) {
                if (url.toString().startsWith("http")) {
                    System.err.println("Cannot receive the response from the url: " + url);
                } else {
                    String path = url.getPath();
                    SourceModule dummy = new SourceURLModule(FileWriter
                            .makeHtmlFile(dir,
                                    path.substring(path.lastIndexOf(File.separator) + 1, path.length() - 1), "")
                            .toURI().toURL());
                    String dummypath = dummy.getName();
                    if (DEBUG)
                        System.err.println("make dummy: " + dummypath);
                    addScopeMap(Atom.findOrCreateAsciiAtom(url.toString()), Atom
                            .findOrCreateAsciiAtom(dummypath.substring(dummypath.lastIndexOf(File.separator) + 1)));
                    scope.addToScope(scope.getJavaScriptLoader(), dummy);
                }
            }
        }

        return scope;
    }

    private Map<Atom, ClassLoaderReference> jsLoaderMap;

    private static void addScopeMap(Atom f, Atom s) {
        nameConvertMap.put(f, s);
        if (DEBUG)
            System.out.println("[scope] " + f + " => " + s);
    }

    public Collection<ClassLoaderReference> getJavaScriptLoaders() {
        return jsLoaderMap.values();
    }

    public ClassLoaderReference getJavaScriptLoader() {
        return getLoader(JavaScriptTypes.jsLoaderName);
    }

    public Collection<Atom> getJavaScriptNames() {
        return nameConvertMap.values();
    }

    public Atom htmlToJs(String html) {
        return nameConvertMap.get(Atom.findOrCreateAsciiAtom(html));
    }
}