blob: ed8d24aa3b8fb883742cdcce164881949a7c6b14 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.coverage;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.ResultReceiver;
import org.jacoco.agent.rt.RT;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
/**
* A service that responds to `cmd coverage ...` and provides a mechanism for dumping code coverage
* information from the system server process.
* @hide
*/
public class CoverageService extends Binder {
public static final String COVERAGE_SERVICE = "coverage";
public static final boolean ENABLED;
static {
// This service should only be enabled if org.jacoco.agent.rt.RT was added to the build
boolean shouldEnable = true;
try {
Class.forName("org.jacoco.agent.rt.RT");
} catch (ClassNotFoundException e) {
shouldEnable = false;
}
ENABLED = shouldEnable;
}
/**
* {@inheritDoc}
*/
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
new CoverageCommand().exec(this, in, out, err, args, callback, resultReceiver);
}
/**
* A {@link ShellCommand} implementation for performing coverage shell commands.
*/
private static class CoverageCommand extends ShellCommand {
/**
* {@inheritDoc}
*/
@Override
public int onCommand(String cmd) {
if ("dump".equals(cmd)) {
return onDump();
} else if ("reset".equals(cmd)) {
return onReset();
} else {
return handleDefaultCommands(cmd);
}
}
/**
* {@inheritDoc}
*/
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
pw.println("Coverage commands:");
pw.println(" help");
pw.println(" Print this help text.");
pw.println(" dump [FILE]");
pw.println(" Dump code coverage to FILE.");
pw.println(" reset");
pw.println(" Reset coverage information.");
}
/**
* Perform the "dump" command to write the collected execution data to a file.
*
* @return The command result.
*/
private int onDump() {
// Figure out where to dump the coverage data
String dest = getNextArg();
if (dest == null) {
dest = "/data/local/tmp/coverage.ec";
} else {
File f = new File(dest);
if (f.isDirectory()) {
dest = new File(f, "coverage.ec").getAbsolutePath();
}
}
// Try to open the destination file
ParcelFileDescriptor fd = openFileForSystem(dest, "w");
if (fd == null) {
return -1;
}
// Write the execution data to the file
try (BufferedOutputStream output = new BufferedOutputStream(
new ParcelFileDescriptor.AutoCloseOutputStream(fd))) {
output.write(RT.getAgent().getExecutionData(false));
output.flush();
getOutPrintWriter().println(String.format("Dumped coverage data to %s", dest));
} catch (IOException e) {
getErrPrintWriter().println("Failed to dump coverage data: " + e.getMessage());
return -1;
}
return 0;
}
/**
* Perform the "reset" command to clear the collected execution data.
*
* @return The command result.
*/
private int onReset() {
RT.getAgent().reset();
getOutPrintWriter().println("Reset coverage data");
return 0;
}
}
}