Skip to content

Commit 58f6b56

Browse files
[controller] add locks to prevent corruption due parallel critical task
1 parent b8d531b commit 58f6b56

1 file changed

Lines changed: 143 additions & 74 deletions

File tree

‎controller/app/src/main/java/org/iiab/controller/DeployFragment.java‎

Lines changed: 143 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public class DeployFragment extends Fragment {
116116
// Native Engine Variables
117117
private static Aria2Manager aria2Manager;
118118
private static boolean isDownloadingRootfs = false;
119+
// State Variables (New control variables)
120+
private boolean isRestoring = false;
121+
private boolean isDeleting = false;
122+
private boolean isImporting = false;
119123
private PRootEngine prootEngine;
120124

121125
// Background Handlers
@@ -591,53 +595,62 @@ else if (isServerRunning)
591595
btnAdvancedForceStop.setOnClickListener(v -> openTermuxAppInfo());
592596
}
593597

594-
if (isServerRunning) {
595-
// CASE A: Server Running (Lock UI)
598+
boolean isBusy = isSystemBusy();
599+
600+
// 1. ALWAYS link the buttons so Listeners can intercept and drop the Snackbar
601+
bindInstallButtonLogic(mainAct, debianRootfs, iiabRootDir);
602+
bindDeleteButtonLogic(mainAct, debianRootfs);
603+
bindBackupButtonLogic(mainAct, backupsDir, iiabRootDir);
604+
bindResetButtonLogic(mainAct, debianRootfs);
605+
bindBackupMenuLogic(backupsDir);
606+
refreshRestoreButtonLogic();
607+
608+
if (isServerRunning || isBusy) {
609+
// LOCK MODE: Server On or System Busy
596610
float lockAlpha = 0.5f;
597-
btnFastInstall.setAlpha(lockAlpha);
598-
btnFastDelete.setAlpha(lockAlpha);
599-
if (btnAdvancedBackup != null) btnAdvancedBackup.setAlpha(lockAlpha);
600-
if (btnAdvancedRestore != null) btnAdvancedRestore.setAlpha(lockAlpha);
601-
if (btnAdvancedReset != null) btnAdvancedReset.setAlpha(lockAlpha);
602-
if (txtSelectBackupTitle != null) txtSelectBackupTitle.setAlpha(lockAlpha);
603611

604-
btnFastInstall.setText(R.string.install_btn_reinstall);
605-
View.OnClickListener serverHot = v -> Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
606-
btnFastInstall.setOnClickListener(serverHot);
607-
btnFastDelete.setOnClickListener(serverHot);
608-
if (btnAdvancedBackup != null) btnAdvancedBackup.setOnClickListener(serverHot);
609-
if (btnAdvancedRestore != null) btnAdvancedRestore.setOnClickListener(serverHot);
610-
if (btnAdvancedReset != null) btnAdvancedReset.setOnClickListener(serverHot);
611-
if (txtSelectBackupTitle != null) txtSelectBackupTitle.setOnClickListener(serverHot);
612+
// We keep the opacity at 80% only for the button that is currently working
613+
btnFastInstall.setAlpha((isDownloadingRootfs && !isServerRunning) ? 0.8f : lockAlpha);
614+
btnFastDelete.setAlpha(isDeleting ? 0.8f : lockAlpha);
615+
if (btnAdvancedBackup != null) btnAdvancedBackup.setAlpha(isBackupInProgress ? 0.8f : lockAlpha);
616+
if (btnAdvancedRestore != null) btnAdvancedRestore.setAlpha(isRestoring ? 0.8f : lockAlpha);
617+
if (btnAdvancedReset != null) btnAdvancedReset.setAlpha((isDownloadingRootfs && !isServerRunning) ? 0.8f : lockAlpha);
618+
if (txtSelectBackupTitle != null) txtSelectBackupTitle.setAlpha(lockAlpha);
619+
if (btnImportBackup != null) btnImportBackup.setAlpha(isImporting ? 0.8f : lockAlpha);
620+
621+
// Lock module checkboxes in the grid
622+
for (CheckBox cb : newInstallCheckboxes) {
623+
cb.setEnabled(false);
624+
View card = (View) cb.getParent().getParent();
625+
card.setAlpha(0.6f);
626+
card.setOnClickListener(v -> {
627+
String msg = isServerRunning ? getString(R.string.install_msg_server_running_lock) : getSystemBusyMessage();
628+
Snackbar.make(v, msg, Snackbar.LENGTH_LONG).show();
629+
});
630+
}
612631

613632
} else {
614-
// CASE B: Server Offline (Enable UI)
633+
// FREE MODE: All off and ready to operate
615634
if (selectedTier == null || !isStorageSafe) btnFastInstall.setAlpha(0.4f);
616635
else btnFastInstall.setAlpha(1.0f);
617636

618637
btnFastDelete.setAlpha(1.0f);
619638
if (btnAdvancedBackup != null) btnAdvancedBackup.setAlpha(1.0f);
620639
if (btnAdvancedReset != null) btnAdvancedReset.setAlpha(1.0f);
621640
if (txtSelectBackupTitle != null) txtSelectBackupTitle.setAlpha(1.0f);
622-
refreshRestoreButtonLogic();
623-
624-
if (!isDownloadingRootfs) {
625-
btnFastInstall.setEnabled(true);
626-
btnFastInstall.setTextSize(14f);
627-
if (isProotInstalled) btnFastInstall.setText(R.string.install_btn_reinstall);
628-
else btnFastInstall.setText(R.string.install_btn_install);
629-
} else {
630-
btnFastInstall.setEnabled(true);
631-
btnFastInstall.setTextSize(12f);
632-
btnFastInstall.setAlpha(0.8f);
641+
if (btnImportBackup != null) btnImportBackup.setAlpha(1.0f);
642+
643+
btnFastInstall.setEnabled(true);
644+
btnFastInstall.setTextSize(14f);
645+
btnFastInstall.setText(isProotInstalled ? R.string.install_btn_reinstall : R.string.install_btn_install);
646+
647+
// Unlock checkboxes
648+
for (CheckBox cb : newInstallCheckboxes) {
649+
cb.setEnabled(true);
650+
View card = (View) cb.getParent().getParent();
651+
card.setAlpha(1.0f);
652+
card.setOnClickListener(v -> cb.toggle());
633653
}
634-
635-
// Bind native buttons
636-
bindInstallButtonLogic(mainAct, debianRootfs, iiabRootDir);
637-
bindDeleteButtonLogic(mainAct, debianRootfs);
638-
bindBackupButtonLogic(mainAct, backupsDir, iiabRootDir);
639-
bindResetButtonLogic(mainAct, debianRootfs);
640-
bindBackupMenuLogic(backupsDir);
641654
}
642655
}
643656

@@ -916,14 +929,13 @@ public void onError(String error) {
916929

917930
private void bindInstallButtonLogic(MainActivity mainAct, File debianRootfs, File iiabRootDir) {
918931
btnFastInstall.setOnClickListener(v -> {
919-
if (selectedTier == null) {
920-
Snackbar.make(v, R.string.install_error_no_tier, Snackbar.LENGTH_LONG).show();
921-
return;
922-
}
923-
if (!isStorageSafe) {
924-
Snackbar.make(v, R.string.install_error_no_storage, Snackbar.LENGTH_LONG).show();
932+
// 1. Main Lock: Server On
933+
if (mainAct.isServerAlive) {
934+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
925935
return;
926936
}
937+
938+
// 2. HIGH PRIORITY: If this button is working, we allow cancel
927939
if (isDownloadingRootfs) {
928940
new android.app.AlertDialog.Builder(requireContext())
929941
.setTitle(getString(R.string.install_btn_cancel_title))
@@ -935,12 +947,30 @@ private void bindInstallButtonLogic(MainActivity mainAct, File debianRootfs, Fil
935947
btnFastInstall.setText(R.string.install_btn_install);
936948
btnFastInstall.setAlpha(1.0f);
937949
Snackbar.make(getView(), R.string.install_msg_cancelled, Snackbar.LENGTH_SHORT).show();
950+
updateDynamicButtons();
938951
})
939952
.setNegativeButton(getString(R.string.cancel), null)
940953
.show();
941954
return;
942955
}
943956

957+
// 3. If it is not working, but the system is busy with something else: LOCK
958+
if (isSystemBusy()) {
959+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
960+
return;
961+
}
962+
963+
// 4. Normal installation startup validations
964+
if (selectedTier == null) {
965+
Snackbar.make(v, R.string.install_error_no_tier, Snackbar.LENGTH_LONG).show();
966+
return;
967+
}
968+
if (!isStorageSafe) {
969+
Snackbar.make(v, R.string.install_error_no_storage, Snackbar.LENGTH_LONG).show();
970+
return;
971+
}
972+
973+
// 5. Start the installation...
944974
Runnable executeDownload = () -> {
945975
enableSystemProtection();
946976
mainAct.invalidateModuleStateTrust();
@@ -1056,10 +1086,22 @@ public void onError(String error) {
10561086

10571087
private void bindDeleteButtonLogic(MainActivity mainAct, File debianRootfs) {
10581088
btnFastDelete.setOnClickListener(v -> {
1089+
if (mainAct.isServerAlive) {
1090+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
1091+
return;
1092+
}
1093+
if (isSystemBusy()) {
1094+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
1095+
return;
1096+
}
1097+
10591098
new android.app.AlertDialog.Builder(requireContext())
10601099
.setTitle(R.string.install_dialog_delete_title)
10611100
.setMessage(R.string.install_dialog_delete_msg)
10621101
.setPositiveButton(R.string.install_btn_delete_confirm, (dialog, which) -> {
1102+
isDeleting = true;
1103+
mainAct.runOnUiThread(this::updateDynamicButtons);
1104+
10631105
mainAct.invalidateModuleStateTrust();
10641106
btnFastDelete.setEnabled(false);
10651107
Snackbar.make(getView(), R.string.install_status_deleting, Snackbar.LENGTH_SHORT).show();
@@ -1068,10 +1110,11 @@ private void bindDeleteButtonLogic(MainActivity mainAct, File debianRootfs) {
10681110
try {
10691111
Process p = Runtime.getRuntime().exec(new String[]{"rm", "-rf", debianRootfs.getAbsolutePath()});
10701112
p.waitFor();
1071-
mainAct.runOnUiThread(this::updateDynamicButtons);
10721113
} catch (Exception e) {
10731114
mainAct.runOnUiThread(() -> Snackbar.make(getView(), getString(R.string.install_error_delete, e.getMessage()), Snackbar.LENGTH_LONG).show());
10741115
} finally {
1116+
isDeleting = false;
1117+
mainAct.runOnUiThread(this::updateDynamicButtons);
10751118
disableSystemProtection();
10761119
}
10771120
}).start();
@@ -1085,42 +1128,15 @@ private void bindResetButtonLogic(MainActivity mainAct, File debianRootfs) {
10851128
if (btnAdvancedReset == null) return;
10861129
btnAdvancedReset.setOnClickListener(v -> {
10871130

1088-
// 1. Safe Abortion Phase
1089-
if (isDownloadingRootfs) {
1090-
new android.app.AlertDialog.Builder(requireContext())
1091-
.setTitle(getString(R.string.install_btn_cancel_title))
1092-
.setMessage(getString(R.string.install_btn_cancel_msg))
1093-
.setPositiveButton(getString(R.string.install_btn_cancel_confirm), (dialog, which) -> {
1094-
if (aria2Manager != null) aria2Manager.stopDownload();
1095-
disableSystemProtection();
1096-
isDownloadingRootfs = false;
1097-
1098-
// We clean the remains of the failed download if they exist
1099-
String arch = getTermuxArch();
1100-
String archSuffix = (arch.contains("arm") && !arch.contains("64")) ? "arm" : "aarch64";
1101-
String tarball = "debian-trixie-" + archSuffix + "-pd-v4.29.0.tar.xz";
1102-
File partialDownload = new File("/storage/emulated/0/Download", tarball);
1103-
if (partialDownload.exists()) partialDownload.delete();
1104-
File ariaState = new File("/storage/emulated/0/Download", tarball + ".aria2");
1105-
if (ariaState.exists()) ariaState.delete();
1106-
1107-
btnAdvancedReset.setText(getString(R.string.install_btn_reset));
1108-
btnAdvancedReset.setEnabled(true);
1109-
updateDynamicButtons();
1110-
Snackbar.make(getView(), R.string.install_msg_cancelled, Snackbar.LENGTH_SHORT).show();
1111-
})
1112-
.setNegativeButton(R.string.cancel, null)
1113-
.show();
1131+
if (mainAct.isServerAlive) {
1132+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
11141133
return;
11151134
}
1116-
1117-
// 2. IF THE SYSTEM IS ALREADY DOING SOMETHING ELSE OR HAS ALREADY STARTED EXTRACTING
1118-
if (btnAdvancedReset.getText().toString().contains("Extract") || btnAdvancedReset.getText().toString().contains("Bootstrap")) {
1119-
Snackbar.make(getView(), "System extraction in progress. Please do not interrupt.", Snackbar.LENGTH_SHORT).show();
1135+
if (isSystemBusy()) {
1136+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
11201137
return;
11211138
}
1122-
1123-
// 3. NORMAL STATE: RESET START
1139+
// NORMAL STATE: RESET START
11241140
new android.app.AlertDialog.Builder(requireContext())
11251141
.setTitle(R.string.install_dialog_reset_title)
11261142
.setMessage(R.string.install_dialog_reset_msg)
@@ -1695,8 +1711,19 @@ private void evaluateLaunchButton() {
16951711

16961712
if (hasSelections) {
16971713
btnLaunchInstall.setOnClickListener(v -> {
1714+
MainActivity mainAct = (MainActivity) getActivity();
1715+
if (mainAct != null && mainAct.isServerAlive) {
1716+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
1717+
return;
1718+
}
1719+
if (isSystemBusy() && !isBatchInstalling) {
1720+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
1721+
return;
1722+
}
1723+
16981724
isBatchInstalling = true;
16991725
saveQueueToPrefs();
1726+
updateDynamicButtons();
17001727
processNextInQueue();
17011728
});
17021729
} else {
@@ -1722,6 +1749,14 @@ private void setupSafLaunchers() {
17221749
private void bindBackupButtonLogic(MainActivity mainAct, File backupsDir, File iiabRootDir) {
17231750
if (btnAdvancedBackup == null) return;
17241751
btnAdvancedBackup.setOnClickListener(v -> {
1752+
if (mainAct.isServerAlive) {
1753+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
1754+
return;
1755+
}
1756+
if (isSystemBusy() && !isBackupInProgress) {
1757+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
1758+
return;
1759+
}
17251760
if (isBackupInProgress) {
17261761
new android.app.AlertDialog.Builder(requireContext())
17271762
.setTitle(getString(R.string.install_msg_backup_in_progress_title))
@@ -1989,11 +2024,24 @@ private void refreshRestoreButtonLogic() {
19892024
} else {
19902025
btnAdvancedRestore.setAlpha(1.0f);
19912026
btnAdvancedRestore.setOnClickListener(v -> {
2027+
if (mainAct.isServerAlive) {
2028+
Snackbar.make(v, R.string.install_msg_server_running_lock, Snackbar.LENGTH_LONG).show();
2029+
return;
2030+
}
2031+
if (isSystemBusy()) {
2032+
Snackbar.make(v, getSystemBusyMessage(), Snackbar.LENGTH_LONG).show();
2033+
return;
2034+
}
2035+
2036+
isRestoring = true;
2037+
updateDynamicButtons();
19922038
Snackbar.make(v, getString(R.string.install_msg_restore_starting, selectedBackupFile), Snackbar.LENGTH_SHORT).show();
19932039
mainAct.invalidateModuleStateTrust();
19942040

19952041
File backupFile = new File(new File(requireContext().getFilesDir(), "rootfs/backups"), selectedBackupFile);
19962042
if (!backupFile.exists()) {
2043+
isRestoring = false;
2044+
updateDynamicButtons();
19972045
Snackbar.make(v, R.string.install_error_backup_missing, Snackbar.LENGTH_SHORT).show();
19982046
return;
19992047
}
@@ -2008,6 +2056,7 @@ private void refreshRestoreButtonLogic() {
20082056
@Override
20092057
public void onComplete(String destDir) {
20102058
mainAct.runOnUiThread(() -> {
2059+
isRestoring = false;
20112060
disableSystemProtection();
20122061
btnAdvancedRestore.setEnabled(true);
20132062
btnAdvancedRestore.setText(getString(R.string.install_btn_restore));
@@ -2019,6 +2068,7 @@ public void onComplete(String destDir) {
20192068
@Override
20202069
public void onError(String error) {
20212070
mainAct.runOnUiThread(() -> {
2071+
isRestoring = false;
20222072
disableSystemProtection();
20232073
btnAdvancedRestore.setEnabled(true);
20242074
btnAdvancedRestore.setText(getString(R.string.install_btn_restore));
@@ -2032,6 +2082,8 @@ public void onError(String error) {
20322082
}
20332083

20342084
private void importBackupSafely(Uri sourceUri) {
2085+
isImporting = true;
2086+
updateDynamicButtons();
20352087
btnImportBackup.setEnabled(false);
20362088
btnImportBackup.setText(getString(R.string.install_msg_importing));
20372089
Snackbar.make(getView(), getString(R.string.install_msg_importing), Snackbar.LENGTH_LONG).show();
@@ -2058,6 +2110,7 @@ private void importBackupSafely(Uri sourceUri) {
20582110

20592111
if (getActivity() != null) {
20602112
getActivity().runOnUiThread(() -> {
2113+
isImporting = false;
20612114
btnImportBackup.setEnabled(true);
20622115
btnImportBackup.setText(getString(R.string.install_btn_import_backup));
20632116
selectedBackupFile = fileName;
@@ -2068,6 +2121,8 @@ private void importBackupSafely(Uri sourceUri) {
20682121
} catch (Exception e) {
20692122
if (getActivity() != null) {
20702123
getActivity().runOnUiThread(() -> {
2124+
isImporting = false;
2125+
updateDynamicButtons();
20712126
btnImportBackup.setEnabled(true);
20722127
btnImportBackup.setText(getString(R.string.install_btn_import_backup));
20732128
Snackbar.make(getView(), getString(R.string.install_msg_import_failed, e.getMessage()), Snackbar.LENGTH_LONG).show();
@@ -2485,6 +2540,20 @@ private void addCpuEntry(float cpuPercentage) {
24852540
// REGION 8: UTILITIES
24862541
// =========================================================================================
24872542

2543+
private boolean isSystemBusy() {
2544+
return isDownloadingRootfs || isBatchInstalling || isBackupInProgress || isRestoring || isDeleting || isImporting;
2545+
}
2546+
2547+
private String getSystemBusyMessage() {
2548+
if (isDownloadingRootfs) return getString(R.string.install_busy_provisioning);
2549+
if (isBatchInstalling) return getString(R.string.install_busy_modules);
2550+
if (isBackupInProgress) return getString(R.string.install_busy_backup);
2551+
if (isRestoring) return getString(R.string.install_busy_restore);
2552+
if (isDeleting) return getString(R.string.install_busy_delete);
2553+
if (isImporting) return getString(R.string.install_busy_import);
2554+
return getString(R.string.install_busy_generic);
2555+
}
2556+
24882557
private void enableSystemProtection() {
24892558
// SAFE CHECK
24902559
if (!isAdded() || getContext() == null) return;

0 commit comments

Comments
 (0)