Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public void startDownload(Context context, String url, RootfsManifest.Target sig
}

// 2. Prepare the download directory and auxiliary files
File downloadDir = new File(context.getFilesDir(), "rootfs/downloads");
File downloadDir = new File(SystemStateEvaluator.rootfsBaseDir(context), "downloads");
if (!downloadDir.exists()) downloadDir.mkdirs();

// Secure DHT file within our app (avoids the com.termux crash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public void startEnvironment() {
* already there) and it records the environment as coming up.
*/
private void doLaunchEnvironment() {
File rootfsDir = new File(activity.getFilesDir(), "rootfs/installed-rootfs/iiab");
File rootfsDir = SystemStateEvaluator.rootfsDir(activity);
host.addToLog(activity.getString(R.string.log_server_booting_native));
host.onStartupBegan(); // ADFA-4837: fill the pre-pdsm silent window
// ADFA-5343a (D1): a fresh environment is starting — restart the service-downtime clock so the
Expand Down Expand Up @@ -301,7 +301,7 @@ public void onError(String error) {
* point is that no service is left writing). Reuses the same pdsm command as the graceful stop.
*/
public void stopEnvironment(Runnable onDone) {
File rootfsDir = new File(activity.getFilesDir(), "rootfs/installed-rootfs/iiab");
File rootfsDir = SystemStateEvaluator.rootfsDir(activity);
host.addToLog(activity.getString(R.string.log_server_stopping_gracefully));
PRootEngine stopEngine = new PRootEngine();
stopEngine.executeInContainer(activity, rootfsDir.getAbsolutePath(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ public final class SystemStateEvaluator {
private SystemStateEvaluator() {
}

/** Where the installed rootfs lives, under the app's files dir. */
private static final String ROOTFS_PATH = "rootfs/installed-rootfs/iiab";
/** The app's rootfs area under its files dir: the installed tree, downloads and backups. */
public static File rootfsBaseDir(Context ctx) {
return new File(ctx.getFilesDir(), "rootfs");
}

/** ADFA-5061: the one place the rootfs path is spelled, so a reader elsewhere
* does not have to write it out again and drift from this one. */
public static java.io.File rootfsDir(Context ctx) {
return new File(ctx.getFilesDir(), ROOTFS_PATH);
/** ADFA-5061, K2GO-568: the one place the rootfs paths are spelled. */
public static File rootfsDir(Context ctx) {
return new File(rootfsBaseDir(ctx), "installed-rootfs/iiab");
}

private static volatile String cachedTermuxArch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ public void addNewSession() {
// -------------------------------------------------------------
// GENERATE ORCHESTRATOR CLI 'iiab' (Monolithic Tool)
// -------------------------------------------------------------
File rootfsDir = new File(activity.getFilesDir(), "rootfs/installed-rootfs/iiab");
File rootfsDir = SystemStateEvaluator.rootfsDir(activity);
File libproot = new File(activity.getApplicationInfo().nativeLibraryDir, "libproot.so");
File prootLoader = new File(activity.getApplicationInfo().nativeLibraryDir, "libproot-loader.so");
File prootLoader32 = new File(activity.getApplicationInfo().nativeLibraryDir, "libproot-loader32.so");
Expand All @@ -674,7 +674,7 @@ public void addNewSession() {
cliStr.append("#!/system/bin/sh\n\n");

// Global script variables
File backupsDir = new File(activity.getFilesDir(), "rootfs/backups");
File backupsDir = new File(SystemStateEvaluator.rootfsBaseDir(activity), "backups");
cliStr.append("ROOTFS_DIR=\"").append(rootfsDir.getAbsolutePath()).append("\"\n");
cliStr.append("BACKUPS_DIR=\"").append(backupsDir.getAbsolutePath()).append("\"\n");
cliStr.append("export PROOT_TMP_DIR=\"").append(tmpDir.getAbsolutePath()).append("\"\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.content.Context;
import android.util.Log;

import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.boxidentity.data.CopyExcludeFiles;
import org.appdevforall.k2go.deploy.domain.ExtractProgress;
import org.appdevforall.k2go.system.domain.TransferRate;
Expand Down Expand Up @@ -73,7 +74,7 @@ public static String suggestedFileName(Context ctx) {
*/
public static boolean streamBackup(Context ctx, OutputStream dest, ProgressListener listener,
AtomicBoolean cancelled) {
File iiabRootDir = new File(ctx.getFilesDir(), "rootfs");
File iiabRootDir = SystemStateEvaluator.rootfsBaseDir(ctx);
File nativeDir = new File(ctx.getApplicationInfo().nativeLibraryDir);
File staticTar = new File(nativeDir, "libtar.so");
String tarBin = staticTar.exists() ? staticTar.getAbsolutePath() : "tar";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Copyright : Copyright (c) 2026 AppDevForAll
* Description : K2GO-427. Bridges one SAF-read archive to a box-visible path the core can ingest.
* proot runs with -r <rootfs> and no separate bind for /library, so box /library maps
* to host <rootfs>/library (EnvironmentControl.rootfs = filesDir/rootfs/installed-rootfs/
* to host <rootfs>/library (SystemStateEvaluator.rootfsDir = filesDir/rootfs/installed-rootfs/
* iiab). This writes the staged archive under host <rootfs>/library/.conex-staging and
* reports the matching box path /library/.conex-staging/<name> for POST /v1/import/item.
* The core default CONEX_STAGING_DIR is /library/.conex-staging (its is_within_dir guard).
Expand All @@ -15,8 +15,8 @@

import android.content.Context;

import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.contentexchange.domain.ExportFilenames;
import org.appdevforall.k2go.env.EnvironmentControl;

import java.io.File;
import java.io.FileOutputStream;
Expand All @@ -32,7 +32,7 @@ public final class BoxImportStaging {
private final File hostDir;

public BoxImportStaging(Context context) {
this.hostDir = new File(EnvironmentControl.rootfs(context), HOST_STAGING_SUBPATH);
this.hostDir = new File(SystemStateEvaluator.rootfsDir(context), HOST_STAGING_SUBPATH);
}

/** The box-visible path for a staged file, as POST /v1/import/item expects it. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ private void attemptVerifyAndExtract(final String path) {
currentCancelKind = DeepOpState.CancelKind.CANCELLABLE; // K2GO-384: verify -- cancellable (kill + hold)
setStep(org.appdevforall.k2go.deploy.domain.ExtractProgress
.stepped(VERIFY_PASS, RESTORE_PASSES, getString(R.string.k2go_br_status_checking)), 0);
final File destParent = new File(getFilesDir(), "rootfs");
final File destParent = org.appdevforall.k2go.SystemStateEvaluator.rootfsBaseDir(this);
new TarExtractor().startExtraction(this, path, destParent.getAbsolutePath(), true,
cancelBeforeExtract, pauseRequested, forceExtractCancel, 0L, // K2GO-554: untrusted import, full listing
new TarExtractor.ExtractionListener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import androidx.core.app.NotificationManagerCompat;

import org.appdevforall.k2go.R;
import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.delivery.data.CrashReportConsent;
import org.appdevforall.k2go.diskguard.data.FirehoseSignalSource;
import org.appdevforall.k2go.diskguard.domain.DiskGuardEscalation;
Expand Down Expand Up @@ -258,7 +259,7 @@ private static boolean actOnFirehose(Context ctx, String source, int streak, Lis
* reap; the next tick catches it (the guard runs every 10 min, so the overlap is unlikely).
*/
private static boolean confirmFirehoseGrowing(Context ctx) {
File varLog = new File(ctx.getFilesDir(), "rootfs/installed-rootfs/iiab/var/log");
File varLog = new File(SystemStateEvaluator.rootfsDir(ctx), "var/log");
long before = totalLogBytes(varLog);
try {
Thread.sleep(GROWTH_PROBE_MS);
Expand Down Expand Up @@ -350,7 +351,7 @@ private static String formatPaths(List<String> paths) {
* the bytes reclaimed, or 0.
*/
private static long reclaimRunawayLog(Context ctx) {
File varLog = new File(ctx.getFilesDir(), "rootfs/installed-rootfs/iiab/var/log");
File varLog = new File(SystemStateEvaluator.rootfsDir(ctx), "var/log");
File biggest = biggestLog(varLog);
if (biggest == null || biggest.length() < RUNAWAY_LOG_MIN_BYTES) return 0L;
long size = biggest.length();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.File;
import java.io.FileOutputStream;
import java.util.Locale;
import org.appdevforall.k2go.SystemStateEvaluator;

public final class EnvironmentControl {

Expand All @@ -38,11 +39,6 @@ public final class EnvironmentControl {

private EnvironmentControl() {}

/** The installed rootfs services directory the pdsm commands run in. */
public static File rootfs(Context ctx) {
return new File(ctx.getApplicationContext().getFilesDir(), "rootfs/installed-rootfs/iiab");
}

/** Optional log sink for the pdsm output lines. */
public interface LineSink { void onLine(String line); }

Expand All @@ -56,7 +52,7 @@ public static void stop(Context ctx, final LineSink log, final Runnable onDone)
// than at the call sites, so every stop clears it. There are three (the reconciler's teardown
// and DeepOp's backup and restore) and an invariant only one of them upholds is one that rots.
EnvironmentProgress.cleared();
new PRootEngine().executeInContainer(ctx.getApplicationContext(), rootfs(ctx).getAbsolutePath(), CMD_STOP,
new PRootEngine().executeInContainer(ctx.getApplicationContext(), SystemStateEvaluator.rootfsDir(ctx).getAbsolutePath(), CMD_STOP,
new PRootEngine.OutputListener() {
@Override public void onOutputLine(String line) {
EnvironmentProgress.line(line); // the shutdown screen names the stopping service
Expand All @@ -81,7 +77,7 @@ public static void stop(Context ctx, final LineSink log, final Runnable onDone)
* proot is never stacked.
*/
public static PRootEngine start(Context ctx, final LineSink log) {
File rootfsDir = rootfs(ctx);
File rootfsDir = SystemStateEvaluator.rootfsDir(ctx);
createFakeSysData(rootfsDir);
PRootEngine engine = new PRootEngine();
EnvironmentProgress.launched(); // ADFA-5365: the launch is the environment's first sign of life
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.system.Os;
import android.util.Log;

import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.env.domain.EnvironmentProcessMatcher;

import java.io.File;
Expand Down Expand Up @@ -51,7 +52,7 @@ private EnvironmentProcess() {
/** The rootfs proot is pointed at, canonical, or null when it cannot be resolved. */
private static String rootfsPath(Context ctx) {
try {
return new File(ctx.getFilesDir(), "rootfs/installed-rootfs/iiab").getCanonicalPath();
return SystemStateEvaluator.rootfsDir(ctx).getCanonicalPath();
} catch (Exception e) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.appdevforall.k2go.ModuleRegistry;
import org.appdevforall.k2go.PRootEngine;
import org.appdevforall.k2go.R;
import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.TarExtractor;
import org.appdevforall.k2go.util.ProcessRunner;
import org.appdevforall.k2go.deploy.domain.ModuleName;
Expand Down Expand Up @@ -299,8 +300,8 @@ public int onStartCommand(Intent intent, int flags, int startId) {
started = true;
rebuildMode = true;
org.appdevforall.k2go.InstallGuard.begin(this); // exclusive: no concurrent proot op
iiabRootDir = new File(getFilesDir(), "rootfs");
debianRootfs = new File(iiabRootDir, "installed-rootfs/iiab");
iiabRootDir = SystemStateEvaluator.rootfsBaseDir(this);
debianRootfs = SystemStateEvaluator.rootfsDir(this);
if (prootEngine == null) prootEngine = new PRootEngine();
startForeground(InstallNotifications.ONGOING_ID, buildNotification(getString(R.string.k2go_dash_rebuilding)));
acquireHardwareLocks();
Expand Down Expand Up @@ -328,8 +329,8 @@ public int onStartCommand(Intent intent, int flags, int startId) {
// isSystemInstalled=false, no global proot kill) until this install reaches a clean terminal.
org.appdevforall.k2go.InstallGuard.begin(this);

iiabRootDir = new File(getFilesDir(), "rootfs");
debianRootfs = new File(iiabRootDir, "installed-rootfs/iiab");
iiabRootDir = SystemStateEvaluator.rootfsBaseDir(this);
debianRootfs = SystemStateEvaluator.rootfsDir(this);

if (isModules) {
// ADFA-4476 slice 3: the service owns the module install queue, so it survives a
Expand Down Expand Up @@ -1768,7 +1769,7 @@ private void forgetTheAbandonedSystem() {
// 1. The transfer. The whole directory: aria2 leaves the tarball, the control file and
// the network profiler's probe files in it, and it is recreated on the next download.
File downloads = (iiabRootDir != null) ? new File(iiabRootDir, "downloads")
: new File(getFilesDir(), "rootfs/downloads");
: new File(SystemStateEvaluator.rootfsBaseDir(this), "downloads");
if (downloads.exists()) {
ProcessRunner.Result rm = ProcessRunner.run(
new String[]{"rm", "-rf", downloads.getAbsolutePath()});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.journeyapps.barcodescanner.ScanOptions;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.ui.dialog.BrandDialog;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import androidx.core.content.ContextCompat;
Expand Down Expand Up @@ -469,7 +470,7 @@ private void releaseHotspot() {
/** Start the rsync share daemon once we have a LAN IP (off the main thread). */
private void ensureDaemon(String ip) {
if (daemonStarted || daemonStarting || userStopped || ip == null) return;
File rootfsDir = new File(requireContext().getFilesDir(), "rootfs/installed-rootfs/iiab");
File rootfsDir = SystemStateEvaluator.rootfsDir(requireContext());
boolean hasLib = rootfsPresent();
if (!hasLib && !shareAnyway) return; // ADFA-4786: don't silently share an empty library; renderStartState shows the notice
// ADFA-4956: serving a live rootfs yields a torn clone. Coordinate as a deep-env op — refuse if
Expand Down Expand Up @@ -507,7 +508,7 @@ private void ensureDaemon(String ip) {

/** ADFA-4786: true only when a real library is installed (dir exists and is non-empty). */
private boolean rootfsPresent() {
File d = new File(requireContext().getFilesDir(), "rootfs/installed-rootfs/iiab");
File d = SystemStateEvaluator.rootfsDir(requireContext());
String[] kids = d.isDirectory() ? d.list() : null;
return kids != null && kids.length > 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public static boolean atLeast(@Nullable String version, int major, int minor, in
/** Installed dash-node version from the rootfs package.json, or null if not found/parseable. */
@Nullable
public static String installed(@NonNull Context ctx) {
File pkg = new File(ctx.getFilesDir(),
"rootfs/installed-rootfs/iiab/library/dashboard/package.json");
File pkg = new File(org.appdevforall.k2go.SystemStateEvaluator.rootfsDir(ctx),
"library/dashboard/package.json");
if (!pkg.exists()) return null;
StringBuilder sb = new StringBuilder();
try (BufferedReader r = new BufferedReader(new FileReader(pkg))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.appdevforall.k2go.R;
import org.appdevforall.k2go.RsyncManager;
import org.appdevforall.k2go.SyncHandshakeHelper;
import org.appdevforall.k2go.SystemStateEvaluator;
import org.appdevforall.k2go.hotspot.LocalHotspotManager;
import org.appdevforall.k2go.sync.domain.ShareConfig;
import org.appdevforall.k2go.sync.transport.NetworkInterfaces;
Expand Down Expand Up @@ -119,7 +120,7 @@ public void startProbe(Context appCtx, ShareConfig shareConfig, SyncHandshakeHel
return;
}

File destDir = new File(appCtx.getFilesDir(), "rootfs/installed-rootfs/iiab");
File destDir = SystemStateEvaluator.rootfsDir(appCtx);
if (!destDir.exists()) destDir.mkdirs();
pendingDestDir = destDir;
repo.postCalculating();
Expand Down
Loading