77import java .io .FileWriter ;
88import java .io .FilenameFilter ;
99import java .io .IOException ;
10- import java .io .UnsupportedEncodingException ;
1110import java .nio .file .Paths ;
1211import java .util .HashMap ;
13- import java .util .Iterator ;
1412import java .util .List ;
1513import java .util .Map .Entry ;
1614import java .util .Set ;
1715
1816import javax .xml .parsers .ParserConfigurationException ;
1917
2018import org .antlr .runtime .RecognitionException ;
21- import org .antlr .runtime .tree .CommonTree ;
2219import org .json .simple .JSONObject ;
2320import org .json .simple .parser .JSONParser ;
2421import org .json .simple .parser .ParseException ;
@@ -62,6 +59,7 @@ public class MutAPK {
6259 static String extraPath = "" ;
6360 static String operatorsDir = "" ;
6461 static boolean multithread = true ;
62+ static boolean ignoreDeadCode = true ;
6563 static String selectionStrategy = "" ;
6664
6765 // Optional arguments
@@ -75,6 +73,10 @@ public class MutAPK {
7573
7674 static HashMap <String , SmaliAST > smaliASTs = new HashMap <String , SmaliAST >();
7775
76+ static HashMap <String , HashMap <String , CallGraphNode >> callGraph = new HashMap <String , HashMap <String , CallGraphNode >>();
77+
78+ static HashMap <String , HashMap <String , CallGraphNode >> deadCode = new HashMap <String , HashMap <String , CallGraphNode >>();
79+
7880 public static void main (String [] args ) {
7981 try {
8082 // long initialTime = System.currentTimeMillis();
@@ -122,102 +124,175 @@ public static void runMutAPK(String[] args) throws NumberFormatException, FileNo
122124 //--------------------------------------------
123125 // Run detection phase for AST-based detectors
124126 //--------------------------------------------
125-
126127 // Generate HashMap with all the ASTs
127128 SourceCodeProcessor scp = new SourceCodeProcessor ();
128129 scp .generateASTsMap (extraPath , appName , smaliASTs );
130+ if (ignoreDeadCode ) {
131+
132+ Long initTime = System .currentTimeMillis ();
133+
134+ // Generate the Call Graph
135+ System .out .println ("## Call Graph Results" );
136+ System .out .println ("" );
137+ System .out .println ("Method Type | Amount" );
138+ System .out .println ("----------------|---------" );
139+
140+ callGraph = CallGraphHelper .getCallGraph (smaliASTs );
141+ int cNDC = 0 ;
142+ int cDC = 0 ;
143+
144+ for (Entry <String , HashMap <String , CallGraphNode >> entry : callGraph .entrySet ()) {
145+ for (Entry <String , CallGraphNode > entryy : entry .getValue ().entrySet ()) {
146+ CallGraphNode cGN = entryy .getValue ();
147+ boolean isDeadCode = methodIsDeadCode (cGN );
148+ if (!isDeadCode ) {
149+ cNDC ++;
150+ } else {
151+ if (deadCode .get (cGN .getUnitName ())!=null ) {
152+ deadCode .get (cGN .getUnitName ()).put (cGN .getId (), cGN );
153+ } else {
154+ HashMap <String , CallGraphNode > temp = new HashMap <String , CallGraphNode >();
155+ temp .put (cGN .getId (), cGN );
156+ deadCode .put (cGN .getUnitName (), temp );
157+ }
158+ cDC ++;
159+ }
160+ }
161+ }
162+ System .out .println ("CalledAndDefined | " +cNDC );
163+ System .out .println ("DeadCode | " +cDC );
164+ System .out .println ("\n ----------------------------------" );
165+
166+ // Check Dead Code Methods
167+
168+ // for(Entry<String, HashMap<String, CallGraphNode>> entry : deadCode.entrySet()) {
169+ // System.out.println(entry.getKey());
170+ // for(Entry<String, CallGraphNode> entryy : entry.getValue().entrySet()) {
171+ // System.out.println(" "+entryy.getKey());
172+ // }
173+ // }
174+
175+ // Prune ASTs
176+ for (Entry <String , SmaliAST > entry : smaliASTs .entrySet ()) {
177+ if (deadCode .get (entry .getKey ())!=null ) {
178+ smaliASTs .put (entry .getKey (), ASTHelper .pruneAST (entry .getValue (),deadCode .get (entry .getKey ())));
179+ }
180+ }
181+
182+ Long duration = (System .currentTimeMillis ()-initTime );
183+ System .out .println ("" );
184+ System .out .println ("> It took " +duration +" miliseconds to remove dead code from APK analysis." );
185+
186+
187+ }
188+ // Generate PFP over pruned ASTs
189+ for (Entry <String , SmaliAST > entry : smaliASTs .entrySet ()) {
190+ SmaliAST temp = entry .getValue ();
191+
192+ HashMap <MutationType , List <MutationLocation >> fileLocations = ASTHelper .findLocations (temp , operatorBundle );
193+ appendLocations (fileLocations , locations );
194+ }
195+
196+ // Report the statistics of the found Potential Fault Locations
197+ Set <MutationType > keys = locations .keySet ();
198+ List <MutationLocation > list = null ;
199+ int totalMutants = 0 ;
200+ System .out .println ("## Amount of Potential Fault Locations per Mutation Operator\n " );
201+ System .out .println ("Amount Mutants | Mutation Operator" );
202+ System .out .println ("----------------|---------------------" );
203+ for (MutationType mutationType : keys ) {
204+ list = locations .get (mutationType );
205+ totalMutants += list .size ();
206+ System .out .println (list .size () + " | " + mutationType );
207+ }
208+
209+ // Check if the amount of PFLocations is lower than the requested by the user
210+ if (totalMutants < amountMutants ) {
211+ throw new MutAPKException ("The total of mutants need to be greater than the amount of mutants asked" );
212+ }
213+ System .out .println ("" );
214+
215+ // Build MutationLocation List
216+ List <MutationLocation > mutationLocationList = MutationLocationListBuilder .buildList (locations );
217+ printLocationList (mutationLocationList , mutantsFolder , appName );
218+ System .out .println ("\n Total Locations: " + mutationLocationList .size ());
219+ System .out .println ();
220+ System .out .println ("--------------------------------------" );
221+
222+ // Select Selector
223+ switch (selectionStrategy ) {
224+ case AMOUNT_MUTANTS_SS :
225+ SelectorAmountMutantsMethod selectorAmountMutantsMethod = new SelectorAmountMutantsMethod ();
226+ SelectorAmountMutants selectorAmountMutants = new SelectorAmountMutants (false , false , totalMutants ,
227+ amountMutants );
228+ mutationLocationList = selectorAmountMutantsMethod .mutantSelector (locations , selectorAmountMutants );
229+ break ;
230+ case REPRESENTATIVE_SUBSET_SS :
231+ SelectorConfidenceInterval selectorConfidenceInterval = new SelectorConfidenceInterval (true , false ,
232+ totalMutants , isRSPerOPerator , confidenceLevel , marginError );
233+ SelectorConfidenceIntervalMethod CIMS = new SelectorConfidenceIntervalMethod ();
234+ mutationLocationList = CIMS .mutantSelector (locations , selectorConfidenceInterval );
235+ break ;
236+ default :
237+ break ;
238+ }
239+ System .out .println ("" );
240+
241+ System .out .println ("## Mutation Process Log" );
242+ System .out .println ();
243+ System .out .println ("```sh" );
244+
245+ // Execute mutation phase
246+ MutationsProcessor mProcessor = new MutationsProcessor ("temp" , appName , mutantsFolder );
247+
248+ // Create de apkhash for the base folder
249+ File manifest = new File (apkAbsolutePath + File .separator + "AndroidManifest.xml" );
250+ File smali = new File (apkAbsolutePath + File .separator + "smali" );
251+ File resource = new File (apkAbsolutePath + File .separator + "res" );
252+
129253
130- // Generate the Call Graph
131-
132- HashMap <String , HashMap <String , CallGraphNode >> callGraph = CallGraphHelper .getCallGraph (smaliASTs );
133-
134- // for(Entry<String, HashMap<String, CallGraphNode>> entry : callGraph.entrySet()) {
135- // System.out.println(entry.getKey());
136- // for(Entry<String, CallGraphNode> entryy : entry.getValue().entrySet()) {
137- // CallGraphNode temp = entryy.getValue();
138- // System.out.println(" "+entryy.getKey()+" "+temp.getCallees().size()+" "+temp.getCallers().size());
139- // }
140- // }
141-
142- // Prune ASTs
143-
144-
145- // // Generate PFP over pruned ASTs
146- // for(Entry<String, SmaliAST> entry : smaliASTs.entrySet()) {
147- // SmaliAST temp = entry.getValue();
148- //
149- // HashMap<MutationType, List<MutationLocation>> fileLocations = ASTHelper.findLocations(temp, operatorBundle);
150- // appendLocations(fileLocations, locations);
151- // }
152- //
153- // // Report the statistics of the found Potential Fault Locations
154- // Set<MutationType> keys = locations.keySet();
155- // List<MutationLocation> list = null;
156- // int totalMutants = 0;
157- // System.out.println("## Amount of Potential Fault Locations per Mutation Operator\n");
158- // System.out.println("Amount Mutants | Mutation Operator");
159- // System.out.println("----------------|---------------------");
160- // for (MutationType mutationType : keys) {
161- // list = locations.get(mutationType);
162- // totalMutants += list.size();
163- // System.out.println(list.size() + " | " + mutationType);
164- // }
165- //
166- // // Check if the amount of PFLocations is lower than the requested by the user
167- // if(totalMutants < amountMutants) {
168- // throw new MutAPKException("The total of mutants need to be greater than the amount of mutants asked");
169- // }
170- // System.out.println("");
171- //
172- // // Build MutationLocation List
173- // List<MutationLocation> mutationLocationList = MutationLocationListBuilder.buildList(locations);
174- // printLocationList(mutationLocationList, mutantsFolder, appName);
175- // System.out.println("\nTotal Locations: " + mutationLocationList.size());
176- // System.out.println();
177- // System.out.println("--------------------------------------");
178- //
179- // // Select Selector
180- // switch (selectionStrategy) {
181- // case AMOUNT_MUTANTS_SS:
182- // SelectorAmountMutantsMethod selectorAmountMutantsMethod = new SelectorAmountMutantsMethod();
183- // SelectorAmountMutants selectorAmountMutants = new SelectorAmountMutants(false, false, totalMutants,
184- // amountMutants);
185- // mutationLocationList = selectorAmountMutantsMethod.mutantSelector(locations, selectorAmountMutants);
186- // break;
187- // case REPRESENTATIVE_SUBSET_SS:
188- // SelectorConfidenceInterval selectorConfidenceInterval = new SelectorConfidenceInterval(true, false,
189- // totalMutants, isRSPerOPerator, confidenceLevel, marginError);
190- // SelectorConfidenceIntervalMethod CIMS = new SelectorConfidenceIntervalMethod();
191- // mutationLocationList = CIMS.mutantSelector(locations, selectorConfidenceInterval);
192- // break;
193- // default:
194- // break;
195- // }
196- // System.out.println("");
197- //
198- // System.out.println("## Mutation Process Log");
199- // System.out.println();
200- // System.out.println("```sh");
201- //
202- // // Execute mutation phase
203- // MutationsProcessor mProcessor = new MutationsProcessor("temp", appName, mutantsFolder);
204- //
205- // // Create de apkhash for the base folder
206- // File manifest = new File(apkAbsolutePath + File.separator + "AndroidManifest.xml");
207- // File smali = new File(apkAbsolutePath + File.separator + "smali");
208- // File resource = new File(apkAbsolutePath + File.separator + "res");
209- //
210- //
211- // // Create ApkHashSeparator
212- // ApkHashSeparator apkHashSeparator = mProcessor.generateApkHashSeparator(manifest, smali, resource, 0);
213- // // Add the base apkHashSeparator
214- // ApkHashOrder.getInstance().setApkHashSeparator(apkHashSeparator);
215- //
216- // if (multithread) {
217- // mProcessor.processMultithreaded(mutationLocationList, extraPath, apkName);
218- // } else {
219- // mProcessor.process(mutationLocationList, extraPath, apkName);
220- // }
254+ // Create ApkHashSeparator
255+ ApkHashSeparator apkHashSeparator = mProcessor .generateApkHashSeparator (manifest , smali , resource , 0 );
256+ // Add the base apkHashSeparator
257+ ApkHashOrder .getInstance ().setApkHashSeparator (apkHashSeparator );
258+
259+ if (multithread ) {
260+ mProcessor .processMultithreaded (mutationLocationList , extraPath , apkName );
261+ } else {
262+ mProcessor .process (mutationLocationList , extraPath , apkName );
263+ }
264+
265+ }
266+
267+ private static boolean methodIsDeadCode (CallGraphNode cGN ) {
268+
269+ String [] exceptions = new String [] {
270+ "<init>" ,
271+ "<clinit>" ,
272+ "init" ,
273+ "onClick" ,
274+ "onCreate" ,
275+ "onOptionsItemSelected" ,
276+ "onCreateOptionsMenu" ,
277+ "onResume" ,
278+ "update" ,
279+ "query" ,
280+ "getType" ,
281+ "insert" ,
282+ "doInBackground" ,
283+ "onPostExecute"
284+ };
285+
286+ if (cGN .getCallers ().size ()>0 ) {
287+ return false ;
288+ }
289+
290+ for (int i = 0 ; i < exceptions .length ; i ++) {
291+ if (cGN .getId ().startsWith (exceptions [i ]+"(" )) {
292+ return false ;
293+ }
294+ }
295+ return true ;
221296
222297 }
223298
@@ -248,9 +323,10 @@ private static void readConfig(String configFilePath) throws NumberFormatExcepti
248323 appName = getVariableValuesString (jsonObject , "appName" );
249324 mutantsFolder = getVariableValuesString (jsonObject , "mutantsFolder" );
250325 multithread = Boolean .valueOf (getVariableValuesString (jsonObject , "multithreadExec" ));
326+ ignoreDeadCode = Boolean .valueOf (getOptionalVariableValuesString (jsonObject , "ignoreDeadCode" ));
251327 selectionStrategy = getVariableValues (jsonObject , "selectionStrategy" );
252- operatorsDir = getOptionalVariableValuesString (jsonObject , "operatorsDir" );
253- extraPath = getOptionalVariableValuesString (jsonObject , "extraPath" );
328+ operatorsDir = getVariableValuesString (jsonObject , "operatorsDir" );
329+ extraPath = getVariableValuesString (jsonObject , "extraPath" );
254330
255331 // Impreme valor por defecto
256332 System .out .println ("" );
@@ -264,6 +340,7 @@ private static void readConfig(String configFilePath) throws NumberFormatExcepti
264340 System .out .println ("extraPath | " + extraPath );
265341 System .out .println ("operatorsDir | " + operatorsDir );
266342 System .out .println ("multithread | " + multithread );
343+ System .out .println ("ignoreDeadCode | " + ignoreDeadCode );
267344 System .out .println ("selectionStrategy | " + selectionStrategy );
268345
269346 JSONObject selectionParameters = (JSONObject ) jsonObject .get ("selectionParameters" );
@@ -398,7 +475,7 @@ private static String getOptionalVariableValuesString(JSONObject jsonObject, Str
398475 if (temp != null ) {
399476 return temp ;
400477 } else {
401- return "" ;
478+ return "true " ;
402479 }
403480 }
404481
0 commit comments