14
14
15
15
package com .google .firebase .crashlytics .internal .persistence ;
16
16
17
+ import android .annotation .SuppressLint ;
18
+ import android .app .Application ;
17
19
import android .content .Context ;
20
+ import android .os .Build .VERSION ;
21
+ import android .os .Build .VERSION_CODES ;
18
22
import androidx .annotation .Nullable ;
19
23
import androidx .annotation .VisibleForTesting ;
20
24
import com .google .firebase .crashlytics .internal .Logger ;
31
35
*
32
36
* <ul>
33
37
* <li>"Common" files, that exist independent of a specific session id.
34
- * <li>"Open session" files, which contain a varierty of temporary files specific ot a Crashlytics
38
+ * <li>"Open session" files, which contain a variety of temporary files specific ot a Crashlytics
35
39
* session. These files may or may not eventually be combined into a Crashlytics crash report
36
40
* file.
37
41
* <li>"Report" files, which are processed reports, ready to be uploaded to Crashlytics servers.
48
52
* convention, any use of new File(...) or similar outside of this class is a code smell.
49
53
*/
50
54
public class FileStore {
51
-
52
- private static final String FILES_PATH = ".com.google.firebase.crashlytics.files.v1 " ;
55
+ private static final String CRASHLYTICS_PATH_V1 = ".com.google.firebase.crashlytics.files.v1" ;
56
+ private static final String CRASHLYTICS_PATH_V2 = ".com.google.firebase.crashlytics.files.v2 " ;
53
57
private static final String SESSIONS_PATH = "open-sessions" ;
54
58
private static final String NATIVE_SESSION_SUBDIR = "native" ;
55
59
private static final String REPORTS_PATH = "reports" ;
56
60
private static final String PRIORITY_REPORTS_PATH = "priority-reports" ;
57
61
private static final String NATIVE_REPORTS_PATH = "native-reports" ;
58
62
59
- private final File rootDir ;
63
+ private final File filesDir ;
64
+ private final File crashlyticsDir ;
60
65
private final File sessionsDir ;
61
66
private final File reportsDir ;
62
67
private final File priorityReportsDir ;
63
68
private final File nativeReportsDir ;
64
69
65
70
public FileStore (Context context ) {
66
- rootDir = prepareBaseDir (new File (context .getFilesDir (), FILES_PATH ));
67
- sessionsDir = prepareBaseDir (new File (rootDir , SESSIONS_PATH ));
68
- reportsDir = prepareBaseDir (new File (rootDir , REPORTS_PATH ));
69
- priorityReportsDir = prepareBaseDir (new File (rootDir , PRIORITY_REPORTS_PATH ));
70
- nativeReportsDir = prepareBaseDir (new File (rootDir , NATIVE_REPORTS_PATH ));
71
+ filesDir = context .getFilesDir ();
72
+ String crashlyticsPath =
73
+ useV2FileSystem ()
74
+ ? CRASHLYTICS_PATH_V2 + File .pathSeparator + sanitizeName (Application .getProcessName ())
75
+ : CRASHLYTICS_PATH_V1 ;
76
+ crashlyticsDir = prepareBaseDir (new File (filesDir , crashlyticsPath ));
77
+ sessionsDir = prepareBaseDir (new File (crashlyticsDir , SESSIONS_PATH ));
78
+ reportsDir = prepareBaseDir (new File (crashlyticsDir , REPORTS_PATH ));
79
+ priorityReportsDir = prepareBaseDir (new File (crashlyticsDir , PRIORITY_REPORTS_PATH ));
80
+ nativeReportsDir = prepareBaseDir (new File (crashlyticsDir , NATIVE_REPORTS_PATH ));
71
81
}
72
82
73
83
@ VisibleForTesting
74
84
public void deleteAllCrashlyticsFiles () {
75
- recursiveDelete (rootDir );
85
+ recursiveDelete (crashlyticsDir );
76
86
}
77
87
78
- public void cleanupLegacyFiles () {
79
- // Fixes b/195664514
80
- // :TODO: consider removing this method in mid 2023, to give all clients time to upgrade
81
- File [] legacyDirs =
82
- new File [] {
83
- new File (rootDir .getParent (), ".com.google.firebase.crashlytics" ),
84
- new File (rootDir .getParent (), ".com.google.firebase.crashlytics-ndk" )
85
- };
88
+ /** Clean up files from previous file systems. */
89
+ public void cleanupPreviousFileSystems () {
90
+ // Clean up pre-versioned file systems.
91
+ cleanupDir (new File (filesDir , ".com.google.firebase.crashlytics" ));
92
+ cleanupDir (new File (filesDir , ".com.google.firebase.crashlytics-ndk" ));
86
93
87
- for (File legacyDir : legacyDirs ) {
88
- if (legacyDir .exists () && recursiveDelete (legacyDir )) {
89
- Logger .getLogger ().d ("Deleted legacy Crashlytics files from " + legacyDir .getPath ());
90
- }
94
+ // Clean up v1 file system.
95
+ if (useV2FileSystem ()) {
96
+ cleanupDir (new File (filesDir , CRASHLYTICS_PATH_V1 ));
97
+ }
98
+ }
99
+
100
+ private void cleanupDir (File dir ) {
101
+ if (dir .exists () && recursiveDelete (dir )) {
102
+ Logger .getLogger ().d ("Deleted previous Crashlytics file system: " + dir .getPath ());
91
103
}
92
104
}
93
105
@@ -103,12 +115,12 @@ static boolean recursiveDelete(File fileOrDirectory) {
103
115
104
116
/** @return internal File used by Crashlytics, that is not specific to a session */
105
117
public File getCommonFile (String filename ) {
106
- return new File (rootDir , filename );
118
+ return new File (crashlyticsDir , filename );
107
119
}
108
120
109
121
/** @return all common (non session specific) files matching the given filter. */
110
122
public List <File > getCommonFiles (FilenameFilter filter ) {
111
- return safeArrayToList (rootDir .listFiles (filter ));
123
+ return safeArrayToList (crashlyticsDir .listFiles (filter ));
112
124
}
113
125
114
126
private File getSessionDir (String sessionId ) {
@@ -193,4 +205,15 @@ private static synchronized File prepareBaseDir(File file) {
193
205
private static <T > List <T > safeArrayToList (@ Nullable T [] array ) {
194
206
return (array == null ) ? Collections .emptyList () : Arrays .asList (array );
195
207
}
208
+
209
+ @ SuppressLint ("AnnotateVersionCheck" )
210
+ private static boolean useV2FileSystem () {
211
+ return VERSION .SDK_INT >= VERSION_CODES .P ;
212
+ }
213
+
214
+ /** Replace potentially unsafe chars with underscores to make a safe file name. */
215
+ @ VisibleForTesting
216
+ static String sanitizeName (String filename ) {
217
+ return filename .replaceAll ("[^a-zA-Z0-9.]" , "_" );
218
+ }
196
219
}
0 commit comments