11
11
import android .view .WindowManager ;
12
12
13
13
import com .termux .R ;
14
+ import com .termux .app .utils .CrashUtils ;
14
15
import com .termux .shared .file .FileUtils ;
15
16
import com .termux .shared .interact .DialogUtils ;
16
17
import com .termux .shared .logger .Logger ;
@@ -70,14 +71,14 @@ static void setupBootstrapIfNeeded(final Activity activity, final Runnable whenD
70
71
71
72
// If prefix directory exists, even if its a symlink to a valid directory and symlink is not broken/dangling
72
73
if (FileUtils .directoryFileExists (PREFIX_FILE_PATH , true )) {
73
- File [] PREFIX_FILE_LIST = PREFIX_FILE .listFiles ();
74
+ File [] PREFIX_FILE_LIST = PREFIX_FILE .listFiles ();
74
75
// If prefix directory is empty or only contains the tmp directory
75
- if (PREFIX_FILE_LIST == null || PREFIX_FILE_LIST .length == 0 || (PREFIX_FILE_LIST .length == 1 && TermuxConstants .TERMUX_TMP_PREFIX_DIR_PATH .equals (PREFIX_FILE_LIST [0 ].getAbsolutePath ()))) {
76
- Logger .logInfo (LOG_TAG , "The prefix directory \" " + PREFIX_FILE_PATH + "\" exists but is empty or only contains the tmp directory." );
77
- } else {
78
- whenDone .run ();
79
- return ;
80
- }
76
+ if (PREFIX_FILE_LIST == null || PREFIX_FILE_LIST .length == 0 || (PREFIX_FILE_LIST .length == 1 && TermuxConstants .TERMUX_TMP_PREFIX_DIR_PATH .equals (PREFIX_FILE_LIST [0 ].getAbsolutePath ()))) {
77
+ Logger .logInfo (LOG_TAG , "The prefix directory \" " + PREFIX_FILE_PATH + "\" exists but is empty or only contains the tmp directory." );
78
+ } else {
79
+ whenDone .run ();
80
+ return ;
81
+ }
81
82
} else if (FileUtils .fileExists (PREFIX_FILE_PATH , false )) {
82
83
Logger .logInfo (LOG_TAG , "The prefix directory \" " + PREFIX_FILE_PATH + "\" does not exist but another file exists at its destination." );
83
84
}
@@ -97,13 +98,15 @@ public void run() {
97
98
// Delete prefix staging directory or any file at its destination
98
99
error = FileUtils .deleteFile ("prefix staging directory" , STAGING_PREFIX_PATH , true );
99
100
if (error != null ) {
100
- throw new RuntimeException (error .toString ());
101
+ showBootstrapErrorDialog (activity , PREFIX_FILE_PATH , whenDone , Error .getErrorMarkdownString (error ));
102
+ return ;
101
103
}
102
104
103
105
// Delete prefix directory or any file at its destination
104
106
error = FileUtils .deleteFile ("prefix directory" , PREFIX_FILE_PATH , true );
105
107
if (error != null ) {
106
- throw new RuntimeException (error .toString ());
108
+ showBootstrapErrorDialog (activity , PREFIX_FILE_PATH , whenDone , Error .getErrorMarkdownString (error ));
109
+ return ;
107
110
}
108
111
109
112
Logger .logInfo (LOG_TAG , "Extracting bootstrap zip to prefix staging directory \" " + STAGING_PREFIX_PATH + "\" ." );
@@ -126,14 +129,22 @@ public void run() {
126
129
String newPath = STAGING_PREFIX_PATH + "/" + parts [1 ];
127
130
symlinks .add (Pair .create (oldPath , newPath ));
128
131
129
- ensureDirectoryExists (new File (newPath ).getParentFile ());
132
+ error = ensureDirectoryExists (new File (newPath ).getParentFile ());
133
+ if (error != null ) {
134
+ showBootstrapErrorDialog (activity , PREFIX_FILE_PATH , whenDone , Error .getErrorMarkdownString (error ));
135
+ return ;
136
+ }
130
137
}
131
138
} else {
132
139
String zipEntryName = zipEntry .getName ();
133
140
File targetFile = new File (STAGING_PREFIX_PATH , zipEntryName );
134
141
boolean isDirectory = zipEntry .isDirectory ();
135
142
136
- ensureDirectoryExists (isDirectory ? targetFile : targetFile .getParentFile ());
143
+ error = ensureDirectoryExists (isDirectory ? targetFile : targetFile .getParentFile ());
144
+ if (error != null ) {
145
+ showBootstrapErrorDialog (activity , PREFIX_FILE_PATH , whenDone , Error .getErrorMarkdownString (error ));
146
+ return ;
147
+ }
137
148
138
149
if (!isDirectory ) {
139
150
try (FileOutputStream outStream = new FileOutputStream (targetFile )) {
@@ -164,23 +175,10 @@ public void run() {
164
175
165
176
Logger .logInfo (LOG_TAG , "Bootstrap packages installed successfully." );
166
177
activity .runOnUiThread (whenDone );
178
+
167
179
} catch (final Exception e ) {
168
- Logger .logStackTraceWithMessage (LOG_TAG , "Bootstrap error" , e );
169
- activity .runOnUiThread (() -> {
170
- try {
171
- new AlertDialog .Builder (activity ).setTitle (R .string .bootstrap_error_title ).setMessage (R .string .bootstrap_error_body )
172
- .setNegativeButton (R .string .bootstrap_error_abort , (dialog , which ) -> {
173
- dialog .dismiss ();
174
- activity .finish ();
175
- }).setPositiveButton (R .string .bootstrap_error_try_again , (dialog , which ) -> {
176
- dialog .dismiss ();
177
- FileUtils .deleteFile ("prefix directory" , PREFIX_FILE_PATH , true );
178
- TermuxInstaller .setupBootstrapIfNeeded (activity , whenDone );
179
- }).show ();
180
- } catch (WindowManager .BadTokenException e1 ) {
181
- // Activity already dismissed - ignore.
182
- }
183
- });
180
+ showBootstrapErrorDialog (activity , PREFIX_FILE_PATH , whenDone , Logger .getStackTracesMarkdownString (null , Logger .getStackTracesStringArray (e )));
181
+
184
182
} finally {
185
183
activity .runOnUiThread (() -> {
186
184
try {
@@ -194,6 +192,30 @@ public void run() {
194
192
}.start ();
195
193
}
196
194
195
+ public static void showBootstrapErrorDialog (Activity activity , String PREFIX_FILE_PATH , Runnable whenDone , String message ) {
196
+ Logger .logErrorExtended (LOG_TAG , "Bootstrap Error:\n " + message );
197
+
198
+ // Send a notification with the exception so that the user knows why bootstrap setup failed
199
+ CrashUtils .sendCrashReportNotification (activity , LOG_TAG , "## Bootstrap Error\n \n " + message , true );
200
+
201
+ activity .runOnUiThread (() -> {
202
+ try {
203
+ new AlertDialog .Builder (activity ).setTitle (R .string .bootstrap_error_title ).setMessage (R .string .bootstrap_error_body )
204
+ .setNegativeButton (R .string .bootstrap_error_abort , (dialog , which ) -> {
205
+ dialog .dismiss ();
206
+ activity .finish ();
207
+ })
208
+ .setPositiveButton (R .string .bootstrap_error_try_again , (dialog , which ) -> {
209
+ dialog .dismiss ();
210
+ FileUtils .deleteFile ("prefix directory" , PREFIX_FILE_PATH , true );
211
+ TermuxInstaller .setupBootstrapIfNeeded (activity , whenDone );
212
+ }).show ();
213
+ } catch (WindowManager .BadTokenException e1 ) {
214
+ // Activity already dismissed - ignore.
215
+ }
216
+ });
217
+ }
218
+
197
219
static void setupStorageSymlinks (final Context context ) {
198
220
final String LOG_TAG = "termux-storage" ;
199
221
@@ -208,7 +230,8 @@ public void run() {
208
230
error = FileUtils .clearDirectory ("~/storage" , storageDir .getAbsolutePath ());
209
231
if (error != null ) {
210
232
Logger .logErrorAndShowToast (context , LOG_TAG , error .getMessage ());
211
- Logger .logErrorExtended (LOG_TAG , error .toString ());
233
+ Logger .logErrorExtended (LOG_TAG , "Setup Storage Error\n " + error .toString ());
234
+ CrashUtils .sendCrashReportNotification (context , LOG_TAG , "## Setup Storage Error\n \n " + Error .getErrorMarkdownString (error ), true );
212
235
return ;
213
236
}
214
237
@@ -245,19 +268,16 @@ public void run() {
245
268
246
269
Logger .logInfo (LOG_TAG , "Storage symlinks created successfully." );
247
270
} catch (Exception e ) {
248
- Logger .logStackTraceWithMessage (LOG_TAG , "Error setting up link" , e );
271
+ Logger .logErrorAndShowToast (context , LOG_TAG , e .getMessage ());
272
+ Logger .logStackTraceWithMessage (LOG_TAG , "Setup Storage Error: Error setting up link" , e );
273
+ CrashUtils .sendCrashReportNotification (context , LOG_TAG , "## Setup Storage Error\n \n " + Logger .getStackTracesMarkdownString (null , Logger .getStackTracesStringArray (e )), true );
249
274
}
250
275
}
251
276
}.start ();
252
277
}
253
278
254
- private static void ensureDirectoryExists (File directory ) {
255
- Error error ;
256
-
257
- error = FileUtils .createDirectoryFile (directory .getAbsolutePath ());
258
- if (error != null ) {
259
- throw new RuntimeException (error .toString ());
260
- }
279
+ private static Error ensureDirectoryExists (File directory ) {
280
+ return FileUtils .createDirectoryFile (directory .getAbsolutePath ());
261
281
}
262
282
263
283
public static byte [] loadZipBytes () {
0 commit comments