Home | History | Annotate | Download | only in fakelibrary
      1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 
      5 package multidex003.fakelibrary;
      6 
      7 import java.io.Closeable;
      8 import java.io.File;
      9 import java.io.FileFilter;
     10 import java.io.IOException;
     11 import java.util.List;
     12 import multidexfakeframeworks.Context;
     13 
     14 /**
     15  * Exposes application secondary dex files as files in the application data
     16  * directory.
     17  */
     18 final class MultiDexExtractor {
     19 
     20     private static final String TAG = MultiDex.TAG;
     21 
     22     /**
     23      * We look for additional dex files named {@code classes2.dex},
     24      * {@code classes3.dex}, etc.
     25      */
     26     private static final String DEX_PREFIX = "classes";
     27     private static final String DEX_SUFFIX = ".dex";
     28 
     29     private static final String EXTRACTED_NAME_EXT = ".classes";
     30     private static final String EXTRACTED_SUFFIX = ".zip";
     31     private static final int MAX_EXTRACT_ATTEMPTS = 3;
     32 
     33     private static final String PREFS_FILE = "multidex.version";
     34     private static final String KEY_TIME_STAMP = "timestamp";
     35     private static final String KEY_CRC = "crc";
     36     private static final String KEY_DEX_NUMBER = "dex.number";
     37 
     38     /**
     39      * Size of reading buffers.
     40      */
     41     private static final int BUFFER_SIZE = 0x4000;
     42     /* Keep value away from 0 because it is a too probable time stamp value */
     43     private static final long NO_VALUE = -1L;
     44 
     45 
     46     private static List<File> loadExistingExtractions(Context context, File sourceApk, File dexDir)
     47             throws IOException {
     48 
     49         final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
     50         int totalDexNumber = 1;
     51         final List<File> files = null;
     52 
     53         for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) {
     54             String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX;
     55             File extractedFile = new File(dexDir, fileName);
     56             if (extractedFile.isFile()) {
     57                 files.add(extractedFile);
     58             } else {
     59                 throw new IOException("Missing extracted secondary dex file '" +
     60                         extractedFile.getPath() + "'");
     61             }
     62         }
     63 
     64         return files;
     65     }
     66 
     67     private static long getTimeStamp(File archive) {
     68         long timeStamp = archive.lastModified();
     69         if (timeStamp == NO_VALUE) {
     70             // never return NO_VALUE
     71             timeStamp--;
     72         }
     73         return timeStamp;
     74     }
     75 
     76 
     77     private static long getZipCrc(File archive) throws IOException {
     78         long computedValue = ZipUtil.getZipCrc(archive);
     79         if (computedValue == NO_VALUE) {
     80             // never return NO_VALUE
     81             computedValue--;
     82         }
     83         return computedValue;
     84     }
     85 
     86     private static List<File> performExtractions(File sourceApk, File dexDir)
     87             throws IOException {
     88 
     89         final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT;
     90 
     91         // Ensure that whatever deletions happen in prepareDexDir only happen if the zip that
     92         // contains a secondary dex file in there is not consistent with the latest apk.  Otherwise,
     93         // multi-process race conditions can cause a crash loop where one process deletes the zip
     94         // while another had created it.
     95         prepareDexDir(dexDir, extractedFilePrefix);
     96 
     97         List<File> files = null;
     98 
     99         return files;
    100     }
    101 
    102     /**
    103      * This removes any files that do not have the correct prefix.
    104      */
    105     private static void prepareDexDir(File dexDir, final String extractedFilePrefix)
    106             throws IOException {
    107         dexDir.mkdir();
    108         if (!dexDir.isDirectory()) {
    109             throw new IOException("Failed to create dex directory " + dexDir.getPath());
    110         }
    111 
    112         // Clean possible old files
    113         FileFilter filter = new FileFilter() {
    114 
    115             @Override
    116             public boolean accept(File pathname) {
    117                 return !pathname.getName().startsWith(extractedFilePrefix);
    118             }
    119         };
    120         File[] files = dexDir.listFiles(filter);
    121         if (files == null) {
    122             return;
    123         }
    124         for (File oldFile : files) {
    125             if (!oldFile.delete()) {
    126             } else {
    127             }
    128         }
    129     }
    130 
    131     /**
    132      * Closes the given {@code Closeable}. Suppresses any IO exceptions.
    133      */
    134     private static void closeQuietly(Closeable closeable) {
    135         try {
    136             closeable.close();
    137         } catch (IOException e) {
    138         }
    139     }
    140 
    141 }
    142