• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.android.car.bugreport;
17 
18 import android.content.Context;
19 
20 import com.google.common.base.Preconditions;
21 
22 import java.io.File;
23 
24 /**
25  * File utilities.
26  *
27  * Thread safety and file operations: All file operations should happen on the same worker
28  * thread for thread safety. This is provided by running both bugreport service and file upload
29  * service on a asynctask. Asynctasks are by default executed on the same worker thread in serial.
30  *
31  * There is one exception to the rule above:
32  * Voice recorder works on main thread, however this is not a thread safety problem because:
33  * i. voice recorder always works before starting to collect rest of the bugreport
34  * ii. a bug report cannot be moved to upload (pending) directory before it is completely
35  * collected.
36  */
37 public class FileUtils {
38     private static final String PREFIX = "bugreport-";
39     /** A directory under the system user; contains bugreport zip files and audio files. */
40     private static final String PENDING_DIR = "bug_reports_pending";
41     // Temporary directory under the current user, used for zipping files.
42     private static final String TEMP_DIR = "bug_reports_temp";
43 
44     private static final String FS = "@";
45 
getPendingDir(Context context)46     static File getPendingDir(Context context) {
47         Preconditions.checkArgument(context.getUser().isSystem(),
48                 "Must be called from the system user.");
49         File dir = new File(context.getDataDir(), PENDING_DIR);
50         dir.mkdirs();
51         return dir;
52     }
53 
54     /**
55      * Returns path to the directory for storing bug report files before they are zipped into a
56      * single file.
57      */
getTempDir(Context context, String timestamp)58     static File getTempDir(Context context, String timestamp) {
59         Preconditions.checkArgument(!context.getUser().isSystem(),
60                 "Must be called from the current user.");
61         File dir = new File(context.getDataDir(), TEMP_DIR + "/" + timestamp);
62         dir.mkdirs();
63         return dir;
64     }
65 
66     /**
67      * Constructs a bugreport zip file name.
68      *
69      * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
70      */
getZipFileName(MetaBugReport bug)71     static String getZipFileName(MetaBugReport bug) {
72         String lookupCode = extractLookupCode(bug);
73         return PREFIX + bug.getUserName() + FS + bug.getTimestamp() + "-" + lookupCode + ".zip";
74     }
75 
76     /**
77      * Constructs a audio message file name.
78      *
79      * <p>Add lookup code to the filename to allow matching audio file and bugreport file in USB.
80      *
81      * @param timestamp - current timestamp, when audio was created.
82      * @param bug       - a bug report.
83      * @param extension - an extension of audio file.
84      */
getAudioFileName(String timestamp, MetaBugReport bug, String extension)85     static String getAudioFileName(String timestamp, MetaBugReport bug, String extension) {
86         String lookupCode = extractLookupCode(bug);
87         return (PREFIX + bug.getUserName() + FS + timestamp
88                 + "-" + lookupCode + "-message." + extension);
89     }
90 
extractLookupCode(MetaBugReport bug)91     public static String extractLookupCode(MetaBugReport bug) {
92         Preconditions.checkArgument(bug.getTitle().startsWith("["),
93                 "Invalid bugreport title, doesn't contain lookup code. ");
94         return bug.getTitle().substring(1, BugReportActivity.LOOKUP_STRING_LENGTH + 1);
95     }
96 
97     /**
98      * Returns a {@link File} object pointing to a path in a temp directory under current users
99      * {@link Context#getDataDir}.
100      *
101      * @param context       - an application context.
102      * @param timestamp     - generates file for this timestamp
103      * @param suffix        - a filename suffix.
104      * @return A file.
105      */
getFileWithSuffix(Context context, String timestamp, String suffix)106     static File getFileWithSuffix(Context context, String timestamp, String suffix) {
107         return new File(getTempDir(context, timestamp), timestamp + suffix);
108     }
109 
110     /**
111      * Returns a {@link File} object pointing to a path in a temp directory under current users
112      * {@link Context#getDataDir}.
113      *
114      * @param context     - an application context.
115      * @param timestamp   - generates file for this timestamp.
116      * @param name        - a filename
117      * @return A file.
118      */
getFile(Context context, String timestamp, String name)119     static File getFile(Context context, String timestamp, String name) {
120         return new File(getTempDir(context, timestamp), name);
121     }
122 
123     /**
124      * Deletes a directory and its contents recursively
125      *
126      * @param directory to delete
127      */
deleteDirectory(File directory)128     static void deleteDirectory(File directory) {
129         File[] files = directory.listFiles();
130         if (files != null) {
131             for (File file : files) {
132                 if (!file.isDirectory()) {
133                     file.delete();
134                 } else {
135                     deleteDirectory(file);
136                 }
137             }
138         }
139         directory.delete();
140     }
141 }
142