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.dx.merge; 18 19 import com.android.dex.Dex; 20 import com.android.dex.DexIndexOverflowException; 21 import com.android.dx.command.dexer.DxContext; 22 23 import java.io.File; 24 import java.io.IOException; 25 26 import java.util.concurrent.atomic.AtomicBoolean; 27 import java.util.concurrent.Executors; 28 import java.util.concurrent.ExecutorService; 29 import java.util.concurrent.TimeUnit; 30 import java.util.Arrays; 31 import java.util.Random; 32 import java.util.HashSet; 33 34 /** 35 * This test tries to merge given dex files at random, a first pass at 2 by 2, followed by 36 * a second pass doing multi-way merges. 37 */ 38 public class MergeTest { 39 40 private static final int NUMBER_OF_TRIES = 1000; 41 42 private static final int WORKER_THREADS = 4; 43 44 private static final ExecutorService executor = Executors.newFixedThreadPool(WORKER_THREADS); 45 46 // Helper task to concurrently run merge tests. 47 static class MergeTask implements Runnable { 48 private final DexMerger dexMerger; 49 private final String[] dexFiles; 50 MergeTask(String[] dexFiles, Dex[] dexesToMerge)51 MergeTask(String[] dexFiles, Dex[] dexesToMerge) throws IOException { 52 this.dexMerger = new DexMerger(dexesToMerge, CollisionPolicy.KEEP_FIRST, new DxContext()); 53 this.dexFiles = dexFiles; 54 } 55 run()56 public void run() { 57 try { 58 dexMerger.merge(); 59 } catch (DexIndexOverflowException e) { 60 // ignore index overflow 61 } catch (Throwable t) { 62 System.err.println("Exception processing DEX files: " + t); 63 System.err.println("Problem merging those dexes: " + Arrays.toString(dexFiles)); 64 System.exit(1); 65 } 66 } 67 } 68 main(String[] args)69 public static void main(String[] args) throws Throwable { 70 Random random = new Random(); 71 HashSet<Integer> seen = new HashSet<>(); 72 for (int pass = 0; pass < 2; pass++) { 73 for (int i = 0; i < NUMBER_OF_TRIES; i++) { 74 // On the first pass only do 2-way merges, then do from 3 to 10 way merges 75 // but not more to avoid dex index overflow. 76 int numDex = pass == 0 ? 2 : random.nextInt(8) + 3; 77 numDex = Math.min(numDex, args.length); 78 String[] fileNames = new String[numDex]; 79 for (int j = 0; j < numDex; ++j) { 80 int fileIndex = random.nextInt(args.length); 81 fileNames[j] = args[fileIndex]; 82 } 83 84 if (!seen.add(fileNames.hashCode())) { 85 // Skip, already seen set of file names with the same hash. 86 continue; 87 } 88 89 Dex[] dexesToMerge = new Dex[numDex]; 90 for (int j = 0; j < numDex; ++j) { 91 try { 92 dexesToMerge[j] = new Dex(new File(fileNames[j])); 93 } catch (IOException e) { 94 System.err.println("Error opening " + fileNames[j]); 95 System.err.println(e); 96 System.exit(1); 97 } 98 } 99 executor.execute(new MergeTask(fileNames, dexesToMerge)); 100 } 101 } 102 executor.shutdown(); 103 executor.awaitTermination(8, TimeUnit.HOURS); 104 } 105 } 106