• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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