Home | History | Annotate | Download | only in coverage
      1 /*
      2  * Copyright (C) 2016 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 
     17 package com.android.server.coverage;
     18 
     19 import android.os.Binder;
     20 import android.os.ParcelFileDescriptor;
     21 import android.os.ShellCallback;
     22 import android.os.ShellCommand;
     23 import android.os.ResultReceiver;
     24 
     25 import org.jacoco.agent.rt.RT;
     26 
     27 import java.io.BufferedOutputStream;
     28 import java.io.File;
     29 import java.io.FileDescriptor;
     30 import java.io.IOException;
     31 import java.io.PrintWriter;
     32 
     33 /**
     34  * A service that responds to `cmd coverage ...` and provides a mechanism for dumping code coverage
     35  * information from the system server process.
     36  * @hide
     37  */
     38 public class CoverageService extends Binder {
     39 
     40     public static final String COVERAGE_SERVICE = "coverage";
     41     public static final boolean ENABLED;
     42 
     43     static {
     44         // This service should only be enabled if org.jacoco.agent.rt.RT was added to the build
     45         boolean shouldEnable = true;
     46         try {
     47             Class.forName("org.jacoco.agent.rt.RT");
     48         } catch (ClassNotFoundException e) {
     49             shouldEnable = false;
     50         }
     51         ENABLED = shouldEnable;
     52     }
     53 
     54     /**
     55      * {@inheritDoc}
     56      */
     57     @Override
     58     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
     59             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
     60         new CoverageCommand().exec(this, in, out, err, args, callback, resultReceiver);
     61     }
     62 
     63     /**
     64      * A {@link ShellCommand} implementation for performing coverage shell commands.
     65      */
     66     private static class CoverageCommand extends ShellCommand {
     67 
     68         /**
     69          * {@inheritDoc}
     70          */
     71         @Override
     72         public int onCommand(String cmd) {
     73             if ("dump".equals(cmd)) {
     74                 return onDump();
     75             } else if ("reset".equals(cmd)) {
     76                 return onReset();
     77             } else {
     78                 return handleDefaultCommands(cmd);
     79             }
     80         }
     81 
     82         /**
     83          * {@inheritDoc}
     84          */
     85         @Override
     86         public void onHelp() {
     87             PrintWriter pw = getOutPrintWriter();
     88             pw.println("Coverage commands:");
     89             pw.println("  help");
     90             pw.println("    Print this help text.");
     91             pw.println("  dump [FILE]");
     92             pw.println("    Dump code coverage to FILE.");
     93             pw.println("  reset");
     94             pw.println("    Reset coverage information.");
     95         }
     96 
     97         /**
     98          * Perform the "dump" command to write the collected execution data to a file.
     99          *
    100          * @return The command result.
    101          */
    102         private int onDump() {
    103             // Figure out where to dump the coverage data
    104             String dest = getNextArg();
    105             if (dest == null) {
    106                 dest = "/data/local/tmp/coverage.ec";
    107             } else {
    108                 File f = new File(dest);
    109                 if (f.isDirectory()) {
    110                     dest = new File(f, "coverage.ec").getAbsolutePath();
    111                 }
    112             }
    113 
    114             // Try to open the destination file
    115             ParcelFileDescriptor fd = openFileForSystem(dest, "w");
    116             if (fd == null) {
    117                 return -1;
    118             }
    119 
    120             // Write the execution data to the file
    121             try (BufferedOutputStream output = new BufferedOutputStream(
    122                     new ParcelFileDescriptor.AutoCloseOutputStream(fd))) {
    123                 output.write(RT.getAgent().getExecutionData(false));
    124                 output.flush();
    125                 getOutPrintWriter().println(String.format("Dumped coverage data to %s", dest));
    126             } catch (IOException e) {
    127                 getErrPrintWriter().println("Failed to dump coverage data: " + e.getMessage());
    128                 return -1;
    129             }
    130 
    131             return 0;
    132         }
    133 
    134         /**
    135          * Perform the "reset" command to clear the collected execution data.
    136          *
    137          * @return The command result.
    138          */
    139         private int onReset() {
    140             RT.getAgent().reset();
    141             getOutPrintWriter().println("Reset coverage data");
    142             return 0;
    143         }
    144     }
    145 }
    146