1/*
2 * Copyright (C) 2014 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
17package dexfuzz.program.mutators;
18
19import dexfuzz.Log;
20import dexfuzz.MutationStats;
21import dexfuzz.Options;
22import dexfuzz.program.MutatableCode;
23import dexfuzz.program.Mutation;
24
25import java.util.List;
26import java.util.Random;
27
28/**
29 * The base class for all classes that can mutate methods.
30 */
31public abstract class CodeMutator {
32  /**
33   * The RNG, passed in by the Program that initialised us.
34   */
35  protected Random rng;
36
37  /**
38   * Used to track which mutations happen.
39   */
40  protected MutationStats stats;
41
42  /**
43   * Used to track mutations that have been applied so far.
44   */
45  protected List<Mutation> mutations;
46
47  /**
48   * The chance, out of 100, that this mutator actually mutates the the program
49   * when asked to by the Program. The default is 50% chance, but each mutator that
50   * extends CodeMutator should its own default.
51   */
52  protected int likelihood = 50;
53
54  /**
55   * This constructor is only intended for use in MutationRecorder...
56   */
57  public CodeMutator() {
58
59  }
60
61  /**
62   * Constructor that all subclasses must call...
63   *
64   * @param rng The RNG that the Program created.
65   */
66  public CodeMutator(Random rng, MutationStats stats, List<Mutation> mutations) {
67    this.rng = rng;
68    this.stats = stats;
69    this.mutations = mutations;
70
71    String name = this.getClass().getSimpleName().toLowerCase();
72
73    if (Options.mutationLikelihoods.containsKey(name)) {
74      likelihood = Options.mutationLikelihoods.get(name);
75      Log.info("Set mutation likelihood to " + likelihood
76          + "% for " + this.getClass().getSimpleName());
77    }
78  }
79
80  /**
81   * When the Program picks a particular mutator to mutate the code, it calls
82   * this function, that determines if the mutator will actually mutate the code.
83   * If so, it then calls the mutationFunction() method, that every subclass CodeMutator
84   * is expected to implement to perform its mutation.
85   *
86   * @return If mutation took place.
87   */
88  public boolean attemptToMutate(MutatableCode mutatableCode) {
89    if (shouldMutate(mutatableCode)) {
90      generateAndApplyMutation(mutatableCode);
91      return true;
92    }
93    Log.info("Skipping mutation.");
94    return false;
95  }
96
97  public void forceMutate(Mutation mutation) {
98    Log.info("Forcing mutation.");
99    applyMutation(mutation);
100  }
101
102  public boolean canBeTriggered() {
103    return (likelihood > 0);
104  }
105
106  /**
107   * Randomly determine if the mutator will actually mutate a method, based on its
108   * provided likelihood of mutation.
109   *
110   * @return If the method should be mutated.
111   */
112  private boolean shouldMutate(MutatableCode mutatableCode) {
113    return ((rng.nextInt(100) < likelihood) && canMutate(mutatableCode));
114  }
115
116  private void generateAndApplyMutation(MutatableCode mutatableCode) {
117    Mutation mutation = generateMutation(mutatableCode);
118    // Always save the mutation.
119    mutations.add(mutation);
120    applyMutation(mutation);
121  }
122
123  /**
124   * A CodeMutator must override this method if there is any reason why could not mutate
125   * a particular method, and return false in that case.
126   */
127  protected boolean canMutate(MutatableCode mutatableCode) {
128    return true;
129  }
130
131  protected abstract Mutation generateMutation(MutatableCode mutatableCode);
132
133  protected abstract void applyMutation(Mutation uncastMutation);
134
135  public abstract Mutation getNewMutation();
136}
137