• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.cts.verifier;
18 
19 import android.app.AlertDialog;
20 import android.content.Context;
21 import android.os.AsyncTask;
22 import android.os.Build;
23 import android.os.Environment;
24 import android.os.FileUtils;
25 import android.os.ParcelFileDescriptor;
26 import android.util.Log;
27 
28 import com.android.compatibility.common.util.FileUtil;
29 import com.android.compatibility.common.util.ICaseResult;
30 import com.android.compatibility.common.util.IInvocationResult;
31 import com.android.compatibility.common.util.IModuleResult;
32 import com.android.compatibility.common.util.ITestResult;
33 import com.android.compatibility.common.util.ResultHandler;
34 import com.android.compatibility.common.util.ScreenshotsMetadataHandler;
35 import com.android.compatibility.common.util.ZipUtil;
36 
37 import org.xmlpull.v1.XmlPullParserException;
38 
39 import java.io.File;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.nio.file.StandardCopyOption;
47 import java.text.SimpleDateFormat;
48 import java.util.Date;
49 import java.util.Locale;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52 
53 /**
54  * Background task to generate a report and save it to external storage.
55  */
56 public class ReportExporter extends AsyncTask<Void, Void, String> {
57     private static final String TAG = ReportExporter.class.getSimpleName();
58     private static final boolean DEBUG = true;
59 
60     public static final String REPORT_DIRECTORY = "VerifierReports";
61     public static final String LOGS_DIRECTORY = "ReportLogFiles";
62 
63     private static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
64     private static final String COMMAND_LINE_ARGS = "";
65     private static final String LOG_URL = null;
66     private static final String REFERENCE_URL = null;
67     private static final String SUITE_NAME_METADATA_KEY = "SuiteName";
68     private static final String SUITE_PLAN = "verifier";
69     private static final String SUITE_BUILD = "0";
70     private static final String ZIP_EXTENSION = ".zip";
71     private final long START_MS = System.currentTimeMillis();
72     private final long END_MS = START_MS;
73     private final Context mContext;
74     private final TestListAdapter mAdapter;
75 
ReportExporter(Context context, TestListAdapter adapter)76     ReportExporter(Context context, TestListAdapter adapter) {
77         this.mContext = context;
78         this.mAdapter = adapter;
79     }
80 
81     //
82     // Copy any ReportLog files created by XTS-Verifier tests into the temp report directory
83     // so that they will get ZIPped into the transmitted file.
84     //
copyReportFiles(File tempDir)85     private void copyReportFiles(File tempDir) {
86         if (DEBUG) {
87             Log.d(TAG, "copyReportFiles(" + tempDir.getAbsolutePath() + ")");
88         }
89 
90         File reportLogFolder =
91                 new File(Environment.getExternalStorageDirectory().getAbsolutePath()
92                         + File.separator
93                         + LOGS_DIRECTORY);
94 
95         copyFilesRecursively(reportLogFolder, tempDir);
96     }
97 
copyFilesRecursively(File source, File destFolder)98     private void copyFilesRecursively(File source, File destFolder) {
99         File[] files = source.listFiles();
100 
101         if (files == null) {
102             return;
103         }
104 
105         for (File file : files) {
106             Path src = Paths.get(file.getAbsolutePath());
107             Path dest = Paths.get(
108                     destFolder.getAbsolutePath()
109                             + File.separator
110                             + file.getName());
111             try {
112                 Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
113             } catch (IOException ex) {
114                 LOG.log(Level.WARNING, "Error copying ReportLog file. IOException: " + ex);
115             }
116             if (file.isDirectory()) {
117                 copyFilesRecursively(file, dest.toFile());
118             }
119         }
120     }
121 
122 
123     @Override
doInBackground(Void... params)124     protected String doInBackground(Void... params) {
125         if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
126             LOG.log(Level.WARNING, "External storage is not writable.");
127             return mContext.getString(R.string.no_storage);
128         }
129         IInvocationResult result;
130         try {
131             TestResultsReport report = new TestResultsReport(mContext, mAdapter);
132             result = report.generateResult();
133         } catch (Exception e) {
134             LOG.log(Level.WARNING, "Couldn't create test results report", e);
135             return mContext.getString(R.string.test_results_error);
136         }
137         // create a directory for XTS Verifier reports
138         File externalStorageDirectory = Environment.getExternalStorageDirectory();
139         File verifierReportsDir = new File(externalStorageDirectory, REPORT_DIRECTORY);
140         verifierReportsDir.mkdirs();
141 
142         String suiteName = Version.getMetadata(mContext, SUITE_NAME_METADATA_KEY);
143         // create a temporary directory for this particular report
144         File tempDir = new File(verifierReportsDir, getReportName(suiteName));
145         tempDir.mkdirs();
146 
147         // Pull in any ReportLogs
148         copyReportFiles(tempDir);
149 
150         // create a File object for a report ZIP file
151         File reportZipFile = new File(
152                 verifierReportsDir, getReportName(suiteName) + ZIP_EXTENSION);
153 
154         try {
155             // Serialize the report
156             String versionName = Version.getVersionName(mContext);
157             ResultHandler.writeResults(suiteName, versionName, SUITE_PLAN, SUITE_BUILD,
158                     result, tempDir, START_MS, END_MS, REFERENCE_URL, LOG_URL,
159                     COMMAND_LINE_ARGS, null);
160 
161             // Serialize the screenshots metadata if at least one exists
162             if (containsScreenshotMetadata(result)) {
163                 ScreenshotsMetadataHandler.writeResults(result, tempDir);
164             }
165 
166             // copy formatting files to the temporary report directory
167             copyFormattingFiles(tempDir);
168 
169             // create a compressed ZIP file containing the temporary report directory
170             ZipUtil.createZip(tempDir, reportZipFile);
171         } catch (IOException | XmlPullParserException e) {
172             LOG.log(Level.WARNING, "I/O exception writing report to storage.", e);
173             return mContext.getString(R.string.no_storage_io_parser_exception);
174         } finally {
175             // delete the temporary directory and its files made for the report
176             FileUtil.recursiveDelete(tempDir);
177         }
178         saveReportOnInternalStorage(reportZipFile);
179         return mContext.getString(R.string.report_saved, reportZipFile.getPath());
180     }
181 
containsScreenshotMetadata(IInvocationResult result)182     private boolean containsScreenshotMetadata(IInvocationResult result) {
183         for (IModuleResult module : result.getModules()) {
184             for (ICaseResult cr : module.getResults()) {
185                 for (ITestResult r : cr.getResults()) {
186                     if (r.getResultStatus() == null) {
187                         continue; // test was not executed, don't report
188                     }
189                     if (r.getTestScreenshotsMetadata() != null) {
190                         return true;
191                     }
192                 }
193             }
194         }
195         return false;
196     }
197 
saveReportOnInternalStorage(File reportZipFile)198     private void saveReportOnInternalStorage(File reportZipFile) {
199         if (DEBUG) {
200             Log.d(TAG, "---- saveReportOnInternalStorage(" + reportZipFile.getAbsolutePath() + ")");
201         }
202         try {
203             ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
204                     reportZipFile, ParcelFileDescriptor.MODE_READ_ONLY);
205             InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
206 
207             File verifierDir = mContext.getDir(REPORT_DIRECTORY, Context.MODE_PRIVATE);
208             File verifierReport = new File(verifierDir, reportZipFile.getName());
209             FileOutputStream fos = new FileOutputStream(verifierReport);
210 
211             FileUtils.copy(is, fos);
212         } catch (Exception e) {
213             LOG.log(Level.WARNING, "I/O exception writing report to internal storage.", e);
214         }
215     }
216 
217     /**
218      * Copy the XML formatting files stored in the assets directory to the result output.
219      *
220      * @param resultsDir
221      */
copyFormattingFiles(File resultsDir)222     private void copyFormattingFiles(File resultsDir) {
223         for (String resultFileName : ResultHandler.RESULT_RESOURCES) {
224             InputStream rawStream = null;
225             try {
226                 rawStream = mContext.getAssets().open(
227                         String.format("report/%s", resultFileName));
228             } catch (IOException e) {
229                 LOG.log(Level.WARNING, "Failed to load " + resultFileName + " from assets.");
230             }
231             if (rawStream != null) {
232                 File resultFile = new File(resultsDir, resultFileName);
233                 try {
234                     FileUtil.writeToFile(rawStream, resultFile);
235                 } catch (IOException e) {
236                     LOG.log(Level.WARNING, "Failed to write " + resultFileName + " to a file.");
237                 }
238             }
239         }
240     }
241 
getReportName(String suiteName)242     private String getReportName(String suiteName) {
243         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss", Locale.ENGLISH);
244         String date = dateFormat.format(new Date());
245         return String.format("%s-%s-%s-%s-%s-%s",
246                 date, suiteName, Build.MANUFACTURER, Build.PRODUCT, Build.DEVICE, Build.ID);
247     }
248 
249     @Override
onPostExecute(String result)250     protected void onPostExecute(String result) {
251         new AlertDialog.Builder(mContext)
252                 .setMessage(result)
253                 .setPositiveButton(android.R.string.ok, null)
254                 .show();
255     }
256 }
257