Add logging for termux bootstrap package installation and setup of storage symlinks

This commit is contained in:
agnostic-apollo
2021-03-24 04:55:10 +05:00
parent 1b5e5b56cb
commit 92b804dc9c
3 changed files with 37 additions and 18 deletions

View File

@@ -28,11 +28,11 @@ import java.util.zip.ZipInputStream;
* Install the Termux bootstrap packages if necessary by following the below steps: * Install the Termux bootstrap packages if necessary by following the below steps:
* <p/> * <p/>
* (1) If $PREFIX already exist, assume that it is correct and be done. Note that this relies on that we do not create a * (1) If $PREFIX already exist, assume that it is correct and be done. Note that this relies on that we do not create a
* broken $PREFIX folder below. * broken $PREFIX directory below.
* <p/> * <p/>
* (2) A progress dialog is shown with "Installing..." message and a spinner. * (2) A progress dialog is shown with "Installing..." message and a spinner.
* <p/> * <p/>
* (3) A staging folder, $STAGING_PREFIX, is {@link #deleteFolder(File)} if left over from broken installation below. * (3) A staging directory, $STAGING_PREFIX, is {@link #deleteDirectory(File)} if left over from broken installation below.
* <p/> * <p/>
* (4) The zip file is loaded from a shared library. * (4) The zip file is loaded from a shared library.
* <p/> * <p/>
@@ -49,16 +49,21 @@ final class TermuxInstaller {
/** Performs setup if necessary. */ /** Performs setup if necessary. */
static void setupIfNeeded(final Activity activity, final Runnable whenDone) { static void setupIfNeeded(final Activity activity, final Runnable whenDone) {
Logger.logInfo(LOG_TAG, "Installing " + TermuxConstants.TERMUX_APP_NAME + " bootstrap packages.");
// Termux can only be run as the primary user (device owner) since only that // Termux can only be run as the primary user (device owner) since only that
// account has the expected file system paths. Verify that: // account has the expected file system paths. Verify that:
UserManager um = (UserManager) activity.getSystemService(Context.USER_SERVICE); UserManager um = (UserManager) activity.getSystemService(Context.USER_SERVICE);
boolean isPrimaryUser = um.getSerialNumberForUser(android.os.Process.myUserHandle()) == 0; boolean isPrimaryUser = um.getSerialNumberForUser(android.os.Process.myUserHandle()) == 0;
if (!isPrimaryUser) { if (!isPrimaryUser) {
new AlertDialog.Builder(activity).setTitle(R.string.bootstrap_error_title).setMessage(R.string.bootstrap_error_not_primary_user_message) String bootstrapErrorMessage = activity.getString(R.string.bootstrap_error_not_primary_user_message, TermuxConstants.TERMUX_PREFIX_DIR_PATH);
Logger.logError(LOG_TAG, bootstrapErrorMessage);
new AlertDialog.Builder(activity).setTitle(R.string.bootstrap_error_title).setMessage(bootstrapErrorMessage)
.setOnDismissListener(dialog -> System.exit(0)).setPositiveButton(android.R.string.ok, null).show(); .setOnDismissListener(dialog -> System.exit(0)).setPositiveButton(android.R.string.ok, null).show();
return; return;
} }
Logger.logInfo(LOG_TAG, "Creating prefix directory \"" + TermuxConstants.TERMUX_PREFIX_DIR_PATH + "\".");
final File PREFIX_FILE = TermuxConstants.TERMUX_PREFIX_DIR; final File PREFIX_FILE = TermuxConstants.TERMUX_PREFIX_DIR;
if (PREFIX_FILE.isDirectory()) { if (PREFIX_FILE.isDirectory()) {
whenDone.run(); whenDone.run();
@@ -74,9 +79,12 @@ final class TermuxInstaller {
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH); final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
if (STAGING_PREFIX_FILE.exists()) { if (STAGING_PREFIX_FILE.exists()) {
deleteFolder(STAGING_PREFIX_FILE); Logger.logInfo(LOG_TAG, "Deleting prefix staging directory \"" + TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH + "\".");
deleteDirectory(STAGING_PREFIX_FILE);
} }
Logger.logInfo(LOG_TAG, "Extracting bootstrap zip to prefix staging directory \"" + TermuxConstants.TERMUX_STAGING_PREFIX_DIR_PATH + "\".");
final byte[] buffer = new byte[8096]; final byte[] buffer = new byte[8096];
final List<Pair<String, String>> symlinks = new ArrayList<>(50); final List<Pair<String, String>> symlinks = new ArrayList<>(50);
@@ -125,10 +133,13 @@ final class TermuxInstaller {
Os.symlink(symlink.first, symlink.second); Os.symlink(symlink.first, symlink.second);
} }
Logger.logInfo(LOG_TAG, "Moving prefix staging to prefix directory.");
if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) { if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) {
throw new RuntimeException("Unable to rename staging folder"); throw new RuntimeException("Moving prefix staging to prefix directory failed");
} }
Logger.logInfo(LOG_TAG, "Bootstrap packages installed successfully.");
activity.runOnUiThread(whenDone); activity.runOnUiThread(whenDone);
} catch (final Exception e) { } catch (final Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Bootstrap error", e); Logger.logStackTraceWithMessage(LOG_TAG, "Bootstrap error", e);
@@ -173,14 +184,14 @@ final class TermuxInstaller {
public static native byte[] getZip(); public static native byte[] getZip();
/** Delete a folder and all its content or throw. Don't follow symlinks. */ /** Delete a directory and all its content or throw. Don't follow symlinks. */
static void deleteFolder(File fileOrDirectory) throws IOException { static void deleteDirectory(File fileOrDirectory) throws IOException {
if (fileOrDirectory.getCanonicalPath().equals(fileOrDirectory.getAbsolutePath()) && fileOrDirectory.isDirectory()) { if (fileOrDirectory.getCanonicalPath().equals(fileOrDirectory.getAbsolutePath()) && fileOrDirectory.isDirectory()) {
File[] children = fileOrDirectory.listFiles(); File[] children = fileOrDirectory.listFiles();
if (children != null) { if (children != null) {
for (File child : children) { for (File child : children) {
deleteFolder(child); deleteDirectory(child);
} }
} }
} }
@@ -192,6 +203,9 @@ final class TermuxInstaller {
static void setupStorageSymlinks(final Context context) { static void setupStorageSymlinks(final Context context) {
final String LOG_TAG = "termux-storage"; final String LOG_TAG = "termux-storage";
Logger.logInfo(LOG_TAG, "Setting up storage symlinks.");
new Thread() { new Thread() {
public void run() { public void run() {
try { try {
@@ -199,18 +213,20 @@ final class TermuxInstaller {
if (storageDir.exists()) { if (storageDir.exists()) {
try { try {
deleteFolder(storageDir); deleteDirectory(storageDir);
} catch (IOException e) { } catch (IOException e) {
Logger.logError(LOG_TAG, "Could not delete old $HOME/storage, " + e.getMessage()); Logger.logStackTraceWithMessage(LOG_TAG, "Failed to delete old ~/storage directory", e);
return; return;
} }
} }
if (!storageDir.mkdirs()) { if (!storageDir.mkdirs()) {
Logger.logError(LOG_TAG, "Unable to mkdirs() for $HOME/storage"); Logger.logError(LOG_TAG, "Unable to create ~/storage directory.");
return; return;
} }
Logger.logInfo(LOG_TAG, "Setting up storage symlinks at ~/storage/shared, ~/storage/downloads, ~/storage/dcim, ~/storage/pictures, ~/storage/music and ~/storage/movies for directories in \"" + Environment.getExternalStorageDirectory().getAbsolutePath() + "\".");
File sharedDir = Environment.getExternalStorageDirectory(); File sharedDir = Environment.getExternalStorageDirectory();
Os.symlink(sharedDir.getAbsolutePath(), new File(storageDir, "shared").getAbsolutePath()); Os.symlink(sharedDir.getAbsolutePath(), new File(storageDir, "shared").getAbsolutePath());
@@ -235,9 +251,12 @@ final class TermuxInstaller {
File dir = dirs[i]; File dir = dirs[i];
if (dir == null) continue; if (dir == null) continue;
String symlinkName = "external-" + i; String symlinkName = "external-" + i;
Logger.logInfo(LOG_TAG, "Setting up storage symlinks at ~/storage/" + symlinkName + " for \"" + dir.getAbsolutePath() + "\".");
Os.symlink(dir.getAbsolutePath(), new File(storageDir, symlinkName).getAbsolutePath()); Os.symlink(dir.getAbsolutePath(), new File(storageDir, symlinkName).getAbsolutePath());
} }
} }
Logger.logInfo(LOG_TAG, "Storage symlinks created successfully.");
} catch (Exception e) { } catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Error setting up link", e); Logger.logStackTraceWithMessage(LOG_TAG, "Error setting up link", e);
} }

View File

@@ -151,7 +151,7 @@ public final class TermuxService extends Service {
if (termuxTmpDir.exists()) { if (termuxTmpDir.exists()) {
try { try {
TermuxInstaller.deleteFolder(termuxTmpDir.getCanonicalFile()); TermuxInstaller.deleteDirectory(termuxTmpDir.getCanonicalFile());
} catch (Exception e) { } catch (Exception e) {
Logger.logStackTraceWithMessage(LOG_TAG, "Error while removing file at " + termuxTmpDir.getAbsolutePath(), e); Logger.logStackTraceWithMessage(LOG_TAG, "Error while removing file at " + termuxTmpDir.getAbsolutePath(), e);
} }

View File

@@ -28,12 +28,12 @@
<string name="toggle_keep_screen_on">Keep screen on</string> <string name="toggle_keep_screen_on">Keep screen on</string>
<string name="autofill_password">Autofill password</string> <string name="autofill_password">Autofill password</string>
<string name="bootstrap_installer_body">Installing…</string> <string name="bootstrap_installer_body">Installing bootstrap packages</string>
<string name="bootstrap_error_title">Unable to install</string> <string name="bootstrap_error_title">Unable to install bootstrap</string>
<string name="bootstrap_error_body">&TERMUX_APP_NAME; was unable to install the bootstrap packages.</string> <string name="bootstrap_error_body">&TERMUX_APP_NAME; was unable to install the bootstrap packages.</string>
<string name="bootstrap_error_abort">Abort</string> <string name="bootstrap_error_abort">Abort</string>
<string name="bootstrap_error_try_again">Try again</string> <string name="bootstrap_error_try_again">Try again</string>
<string name="bootstrap_error_not_primary_user_message">&TERMUX_APP_NAME; can only be installed on the primary user account.</string> <string name="bootstrap_error_not_primary_user_message">&TERMUX_APP_NAME; can only be run as the primary user.\nBootstrap binaries compiled for &TERMUX_APP_NAME; have hardcoded $PREFIX path and cannot be installed under any path other than \"%1$s\".</string>
<string name="max_terminals_reached_title">Max terminals reached</string> <string name="max_terminals_reached_title">Max terminals reached</string>
<string name="max_terminals_reached_message">Close down existing ones before creating new.</string> <string name="max_terminals_reached_message">Close down existing ones before creating new.</string>