summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/Android.mk5
-rw-r--r--services/coverage/Android.mk12
-rw-r--r--services/coverage/java/com/android/server/coverage/CoverageService.java145
-rw-r--r--services/java/com/android/server/SystemServer.java7
4 files changed, 169 insertions, 0 deletions
diff --git a/services/Android.mk b/services/Android.mk
index 291198303548..0d57efe27833 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -24,6 +24,7 @@ services := \
appwidget \
autofill \
backup \
+ coverage\
devicepolicy \
midi \
net \
@@ -37,6 +38,10 @@ services := \
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
+ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
+LOCAL_EMMA_INSTRUMENT := true
+endif
+
include $(BUILD_JAVA_LIBRARY)
# native library
diff --git a/services/coverage/Android.mk b/services/coverage/Android.mk
new file mode 100644
index 000000000000..da99994d6b4c
--- /dev/null
+++ b/services/coverage/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.coverage
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := jacocoagent
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/coverage/java/com/android/server/coverage/CoverageService.java b/services/coverage/java/com/android/server/coverage/CoverageService.java
new file mode 100644
index 000000000000..d600aa8c4276
--- /dev/null
+++ b/services/coverage/java/com/android/server/coverage/CoverageService.java
@@ -0,0 +1,145 @@
+/*
+ * 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 = openOutputFileForSystem(dest);
+ 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;
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7ccae2c323e4..1d550d294560 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -63,6 +63,7 @@ import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MetricsLoggerService;
+import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.display.NightDisplayService;
@@ -1260,6 +1261,12 @@ public final class SystemServer {
traceEnd();
}
+ if (!disableNonCoreServices && CoverageService.ENABLED) {
+ traceBeginAndSlog("AddCoverageService");
+ ServiceManager.addService(CoverageService.COVERAGE_SERVICE, new CoverageService());
+ traceEnd();
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
traceBeginAndSlog("StartPrintManager");
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);