Home | History | Annotate | Download | only in multidex
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.multidex;
     18 
     19 import com.android.dx.cf.direct.DirectClassFile;
     20 import com.android.dx.rop.cst.Constant;
     21 import com.android.dx.rop.cst.ConstantPool;
     22 import com.android.dx.rop.cst.CstType;
     23 import com.android.dx.rop.type.Type;
     24 import com.android.dx.rop.type.TypeList;
     25 
     26 import java.io.FileNotFoundException;
     27 import java.io.IOException;
     28 import java.util.Enumeration;
     29 import java.util.HashSet;
     30 import java.util.Set;
     31 import java.util.zip.ZipEntry;
     32 import java.util.zip.ZipFile;
     33 
     34 /**
     35  * Tool to find direct class references to other classes.
     36  */
     37 public class ClassReferenceListBuilder {
     38     private static final String CLASS_EXTENSION = ".class";
     39 
     40     private Path path;
     41     private Set<String> classNames = new HashSet<String>();
     42 
     43     public ClassReferenceListBuilder(Path path) {
     44         this.path = path;
     45     }
     46 
     47     /**
     48      * Kept for compatibility with the gradle integration, this method just forwards to
     49      * {@link MainDexListBuilder#main(String[])}.
     50      * @deprecated use {@link MainDexListBuilder#main(String[])} instead.
     51      */
     52     @Deprecated
     53     public static void main(String[] args) {
     54         MainDexListBuilder.main(args);
     55     }
     56 
     57     /**
     58      * @param jarOfRoots Archive containing the class files resulting of the tracing, typically
     59      * this is the result of running ProGuard.
     60      */
     61     public void addRoots(ZipFile jarOfRoots) throws IOException {
     62 
     63         // keep roots
     64         for (Enumeration<? extends ZipEntry> entries = jarOfRoots.entries();
     65                 entries.hasMoreElements();) {
     66             ZipEntry entry = entries.nextElement();
     67             String name = entry.getName();
     68             if (name.endsWith(CLASS_EXTENSION)) {
     69                 classNames.add(name.substring(0, name.length() - CLASS_EXTENSION.length()));
     70             }
     71         }
     72 
     73         // keep direct references of roots (+ direct references hierarchy)
     74         for (Enumeration<? extends ZipEntry> entries = jarOfRoots.entries();
     75                 entries.hasMoreElements();) {
     76             ZipEntry entry = entries.nextElement();
     77             String name = entry.getName();
     78             if (name.endsWith(CLASS_EXTENSION)) {
     79                 DirectClassFile classFile;
     80                 try {
     81                     classFile = path.getClass(name);
     82                 } catch (FileNotFoundException e) {
     83                     throw new IOException("Class " + name +
     84                             " is missing form original class path " + path, e);
     85                 }
     86 
     87                 addDependencies(classFile.getConstantPool());
     88             }
     89         }
     90     }
     91 
     92     Set<String> getClassNames() {
     93         return classNames;
     94     }
     95 
     96     private void addDependencies(ConstantPool pool) {
     97         for (Constant constant : pool.getEntries()) {
     98             if (constant instanceof CstType) {
     99                 Type type = ((CstType) constant).getClassType();
    100                 String descriptor = type.getDescriptor();
    101                 if (descriptor.endsWith(";")) {
    102                     int lastBrace = descriptor.lastIndexOf('[');
    103                     if (lastBrace < 0) {
    104                         addClassWithHierachy(descriptor.substring(1, descriptor.length()-1));
    105                     } else {
    106                         assert descriptor.length() > lastBrace + 3
    107                         && descriptor.charAt(lastBrace + 1) == 'L';
    108                         addClassWithHierachy(descriptor.substring(lastBrace + 2,
    109                                 descriptor.length() - 1));
    110                     }
    111                 }
    112             }
    113         }
    114     }
    115 
    116     private void addClassWithHierachy(String classBinaryName) {
    117         if (classNames.contains(classBinaryName)) {
    118             return;
    119         }
    120 
    121         try {
    122             DirectClassFile classFile = path.getClass(classBinaryName + CLASS_EXTENSION);
    123             classNames.add(classBinaryName);
    124             CstType superClass = classFile.getSuperclass();
    125             if (superClass != null) {
    126                 addClassWithHierachy(superClass.getClassType().getClassName());
    127             }
    128 
    129             TypeList interfaceList = classFile.getInterfaces();
    130             int interfaceNumber = interfaceList.size();
    131             for (int i = 0; i < interfaceNumber; i++) {
    132                 addClassWithHierachy(interfaceList.getType(i).getClassName());
    133             }
    134         } catch (FileNotFoundException e) {
    135             // Ignore: The referenced type is not in the path it must be part of the libraries.
    136         }
    137     }
    138 
    139 }
    140