Home | History | Annotate | Download | only in monkey
      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.monkey;
     18 
     19 import com.android.tradefed.log.ITestLogger;
     20 import com.android.tradefed.log.LogUtil.CLog;
     21 import com.android.tradefed.result.FileInputStreamSource;
     22 import com.android.tradefed.result.InputStreamSource;
     23 import com.android.tradefed.result.LogDataType;
     24 import com.android.tradefed.util.CommandResult;
     25 import com.android.tradefed.util.CommandStatus;
     26 import com.android.tradefed.util.FileUtil;
     27 import com.android.tradefed.util.RunUtil;
     28 
     29 import java.io.File;
     30 import java.io.IOException;
     31 
     32 /**
     33  * A utility class that encapsulates details of calling post-processing scripts to generate monkey
     34  * ANR reports.
     35  */
     36 public class AnrReportGenerator {
     37 
     38     private static final long REPORT_GENERATION_TIMEOUT = 30 * 1000; // 30s
     39 
     40     private File mCachedMonkeyLog = null;
     41     private File mCachedBugreport = null;
     42 
     43     private final String mReportScriptPath;
     44     private final String mReportBasePath;
     45     private final String mReportUrlPrefix;
     46     private final String mReportPath;
     47     private final String mDeviceSerial;
     48 
     49     private String mBuildId = null;
     50     private String mBuildFlavor = null;
     51 
     52     /**
     53      * Constructs the instance with details of report script and output location information. See
     54      * matching options on {@link MonkeyBase} for more info.
     55      */
     56     public AnrReportGenerator(String reportScriptPath, String reportBasePath,
     57             String reportUrlPrefix, String reportPath,
     58             String buildId, String buildFlavor, String deviceSerial) {
     59         mReportScriptPath = reportScriptPath;
     60         mReportBasePath = reportBasePath;
     61         mReportUrlPrefix = reportUrlPrefix;
     62         mReportPath = reportPath;
     63         mBuildId = buildId;
     64         mBuildFlavor = buildFlavor;
     65         mDeviceSerial = deviceSerial;
     66 
     67         if (mReportBasePath == null || mReportPath == null || mReportScriptPath == null
     68                 || mReportUrlPrefix == null) {
     69             throw new IllegalArgumentException("ANR post-processing enabled but missing "
     70                     + "required parameters!");
     71         }
     72     }
     73 
     74     /**
     75      * Return the storage sub path based on build info. The path will not include trailing path
     76      * separator.
     77      */
     78     private String getPerBuildStoragePath() {
     79         if (mBuildId == null) {
     80             mBuildId = "-1";
     81         }
     82         if (mBuildFlavor == null) {
     83             mBuildFlavor = "unknown_flavor";
     84         }
     85         return String.format("%s/%s", mBuildId, mBuildFlavor);
     86     }
     87 
     88     /**
     89      * Sets bugreport information for ANR post-processing script
     90      * @param bugreportStream
     91      */
     92     public void setBugReportInfo(InputStreamSource bugreportStream) throws IOException {
     93         if (mCachedBugreport != null) {
     94             CLog.w("A bugreport for this invocation already existed at %s, overriding anyways",
     95                     mCachedBugreport.getAbsolutePath());
     96         }
     97         mCachedBugreport = FileUtil.createTempFile("monkey-anr-report-bugreport", ".txt");
     98         FileUtil.writeToFile(bugreportStream.createInputStream(), mCachedBugreport);
     99     }
    100 
    101     /**
    102      * Sets monkey log information for ANR post-processing script
    103      * @param monkeyLogStream
    104      */
    105     public void setMonkeyLogInfo(InputStreamSource monkeyLogStream) throws IOException {
    106         if (mCachedMonkeyLog != null) {
    107             CLog.w("A monkey log for this invocation already existed at %s, overriding anyways",
    108                     mCachedMonkeyLog.getAbsolutePath());
    109         }
    110         mCachedMonkeyLog = FileUtil.createTempFile("monkey-anr-report-monkey-log", ".txt");
    111         FileUtil.writeToFile(monkeyLogStream.createInputStream(), mCachedMonkeyLog);
    112     }
    113 
    114     public boolean genereateAnrReport(ITestLogger logger) {
    115         if (mCachedMonkeyLog == null || mCachedBugreport == null) {
    116             CLog.w("Cannot generate report: bugreport or monkey log not populated yet.");
    117             return false;
    118         }
    119         // generate monkey report and log it
    120         File reportPath = new File(mReportBasePath,
    121                 String.format("%s/%s", mReportPath, getPerBuildStoragePath()));
    122         if (reportPath.exists()) {
    123             if (!reportPath.isDirectory()) {
    124                 CLog.w("The expected report storage path is not a directory: %s",
    125                         reportPath.getAbsolutePath());
    126                 return false;
    127             }
    128         } else {
    129             if (!reportPath.mkdirs()) {
    130                 CLog.w("Failed to create report storage directory: %s",
    131                         reportPath.getAbsolutePath());
    132                 return false;
    133             }
    134         }
    135         // now we should have the storage path, calculate the HTML report path
    136         // HTML report file should be named as:
    137         // monkey-anr-report-<device serial>-<random string>.html
    138         // under the pre-constructed base report storage path
    139         File htmlReport = null;
    140         try {
    141             htmlReport = FileUtil.createTempFile(
    142                     String.format("monkey-anr-report-%s-", mDeviceSerial), ".html",
    143                     reportPath);
    144         } catch (IOException ioe) {
    145             CLog.e("Error getting place holder file for HTML report.");
    146             CLog.e(ioe);
    147             return false;
    148         }
    149         // now ready to call the script
    150         String htmlReportPath = htmlReport.getAbsolutePath();
    151         String command[] = {
    152                 mReportScriptPath, "--monkey", mCachedMonkeyLog.getAbsolutePath(), "--html",
    153                 htmlReportPath, mCachedBugreport.getAbsolutePath()
    154         };
    155         CommandResult cr = RunUtil.getDefault().runTimedCmdSilently(REPORT_GENERATION_TIMEOUT,
    156                 command);
    157         if (cr.getStatus() == CommandStatus.SUCCESS) {
    158             // Test log the generated HTML report
    159             InputStreamSource source = new FileInputStreamSource(htmlReport);
    160             logger.testLog("monkey-anr-report", LogDataType.HTML, source);
    161             // Clean up and declare success!
    162             source.cancel();
    163             FileUtil.deleteFile(htmlReport);
    164             return true;
    165         } else {
    166             CLog.w(cr.getStderr());
    167             return false;
    168         }
    169     }
    170 
    171     public void cleanTempFiles() {
    172         FileUtil.deleteFile(mCachedBugreport);
    173         FileUtil.deleteFile(mCachedMonkeyLog);
    174     }
    175 }
    176