I am writing an apk analysis program. I cannot go deep into details because it's research material. However, the point is that from time to time when I execute the analysis routine, I get the following message:
Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread "main"
This happens if I do not override the UncaughtExceptionHandler and also if I do, as you'll see from the code below. Since there is no stacktrace data I cannot know where that exception is coming from and what its cause really is.
I hope you can help me...
This is only the main code. There are three main operation that I have to execute. In order not to disclose particular information, I renamed them to A, B and C
public class MainScannerSequential {
public static void main(String[] args) throws ParserConfigurationException, IOException, InterruptedException {
final File target = new File(args[1]);
final File result = new File(args[2]);
final Options options = new Options(args);
silentMode = options.contains("-s");
noA = options.contains("-nl");
noC = options.contains("-ne");
aStrategy = Factory.createA();
bScanner = Factory.createB();
cDetector = Factory.createcC();
examinedFiles = new PersistentFileList(Globals.EXAMINED_FILES_LIST_FILE);
if (result.exists())
resultsWriter = new BufferedWriter(new FileWriter(result, true));
else {
resultsWriter = new BufferedWriter(new FileWriter(result));
resultsWriter.write("***");
resultsWriter.newLine();
}
if (Globals.PERFORMANCE_FILE.exists())
performancesWriter = new BufferedWriter(new FileWriter(Globals.PERFORMANCE_FILE, true));
else {
performancesWriter = new BufferedWriter(new FileWriter(Globals.PERFORMANCE_FILE));
performancesWriter.write("***");
performancesWriter.newLine();
}
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
if ((t != null) && (t.getName() != null))
System.out.println("In thread : " + t.getName());
if ((e != null) && (e.getMessage() != null)) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
if (e.getStackTrace() != null)
for (StackTraceElement ste : e.getStackTrace())
if (ste != null)
System.out.println(ste.getFileName() + " at line " + ste.getLineNumber());
}
}
});
if (target.isDirectory()) {
enumerateDirectory(target);
} else {
String name = target.getName().toLowerCase();
if (name.endsWith(".apklist"))
readFileList(target);
else if (name.endsWith(".apk"))
checkFile(target);
}
closeWriters();
}
private static void println(String message) {
if (!silentMode)
System.out.println(message);
}
private static void print(String message) {
if (!silentMode)
System.out.print(message);
}
private static void enumerateDirectory(File directory) {
for (File file : directory.listFiles()) {
checkFile(file);
if (file.isDirectory())
enumerateDirectory(file);
}
}
private static void readFileList(File file) {
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while((line = reader.readLine()) != null) {
File readFile = new File(line);
if (readFile.exists())
checkFile(readFile);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void checkFile(File file) {
if (examinedFiles.contains(file)) {
println("Skipped: " + file.getName());
return;
}
if (!file.getName().toLowerCase().endsWith(".apk")) {
return;
}
final Wrapper<Double> unpackingTime = new Wrapper<Double>(0.0);
final ApplicationData data = unpack(file, unpackingTime);
if (data == null) {
return;
}
scanData(data, unpackingTime.value);
}
private static ApplicationData unpack(final File file, final Wrapper<Double> unpackingTime) {
final Wrapper<ApplicationData> resultWrapper = new Wrapper<ApplicationData>(null);
final Wrapper<Exception> exceptionWrapper = new Wrapper<Exception>(null);
println("Unpacking: " + file.getName());
unpackingTime.value = Stopwatch.time(new Runnable() {
@Override
public void run() {
try {
resultWrapper.value = ApplicationData.open(file);
} catch (Exception e) {
exceptionWrapper.value = e;
}
}
});
if (resultWrapper.value != null)
println("Unpacked: " + file.getName());
else if (exceptionWrapper.value != null)
println("Dropped: " + file.getName() + " : " + exceptionWrapper.value.getMessage());
return resultWrapper.value;
}
private static void scanData(final ApplicationData applicationData, Double unpackingTime) {
String apkName = applicationData.getDecodedPackage().getOriginalApk().getAbsolutePath();
println("Submitted: " + apkName);
examinedFiles.add(applicationData.getDecodedPackage().getOriginalApk());
final Wrapper<Boolean> aDetected = new Wrapper<Boolean>(false);
final Wrapper<Result> bDetected = new Wrapper<Result>(new Result());
final Wrapper<Boolean> cDetected = new Wrapper<Boolean>(false);
final Wrapper<Double> aDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);
final Wrapper<Double> bDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);
final Wrapper<Double> cDetectionTime = new Wrapper<Double>((double)ANALYSIS_TIMEOUT);
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Runnable() {
@Override
public void run() {
textDetectionTime.value = Stopwatch.time(new Runnable() {
@Override
public void run() {
bScanner.setUnpackedApkDirectory(applicationData.getDecodedPackage().getDecodedDirectory());
bDetected.value = bScanner.evaluate();
}
});
}
});
if (!noA)
executor.submit(new Runnable() {
@Override
public void run() {
lockDetectionTime.value = Stopwatch.time(new Runnable() {
@Override
public void run() {
aStrategy.setTarget(applicationData.getDecodedPackage());
aDetected.value = aStrategy.detect();
}
});
}
});
if (!noC)
executor.submit(new Runnable() {
@Override
public void run() {
encryptionDetectionTime.value = Stopwatch.time(new Runnable() {
@Override
public void run() {
cDetector.setTarget(applicationData.getDecodedPackage());
cDetected.value = cDetector.detect();
}
});
}
});
boolean timedOut = false;
executor.shutdown();
try {
if (!executor.awaitTermination(ANALYSIS_TIMEOUT, TimeUnit.SECONDS)) {
executor.shutdownNow();
timedOut = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
resultsWriter.write(String.format("%s, %b, %b, %f, %b, \"%s\", %b\n",
apkName,
aDetected.value,
bDetected.value.isAccepted(),
bDetected.value.getScore(),
cDetected.value,
bDetected.value.getComment(),
timedOut));
performancesWriter.write(String.format("%s, %f, %f, %f, %f, %d, %dl, %dl\n",
apkName,
aDetectionTime.value,
bDetectionTime.value,
cDetectionTime.value,
unpackingTime,
applicationData.getSmaliLoader().getClassesCount(),
applicationData.getSmaliLoader().getTotalClassesSize(),
applicationData.getDecodedPackage().getOriginalApk().length()));
resultsWriter.flush();
performancesWriter.flush();
} catch (IOException e) { }
// No longer deleting temp files
if (!timedOut)
println("Completed: " + apkName);
else {
print("Timeout");
if (bDetectionTime.value == 0) print(" TextDetection");
if (!noA && (aDetectionTime.value == 0)) print(" LockDetection");
if (!noC && (cDetectionTime.value == 0)) print(" EncryptionDetection");
println(": " + apkName);
}
}
private static void closeWriters() throws IOException {
resultsWriter.close();
performancesWriter.close();
examinedFiles.dispose();
}
private static final int ANALYSIS_TIMEOUT = 40; // seconds
private static Boolean silentMode = false;
private static Boolean noA = false;
private static Boolean noC = false;
private static PersistentFileList examinedFiles;
private static BufferedWriter resultsWriter;
private static BufferedWriter performancesWriter;
private static A aStrategy;
private static B bScanner;
private static C cDetector;
}
I labeled the question as multithread because the same happens in the multithreaded version, which I serialized using this code in order to debug that error. Notice that the NullPointerException is in thread main, not in other Executor-spawned threads.