v2.2.3: Os.chmod() syscall + PRoot fallback + explicit sh invocation for SELinux bypass
This commit is contained in:
@@ -1182,6 +1182,8 @@
|
||||
activePid: null,
|
||||
activeStreamId: null,
|
||||
devToolsInstalled: false,
|
||||
hasProot: false,
|
||||
prootPath: '',
|
||||
commandQueue: []
|
||||
};
|
||||
|
||||
@@ -1919,6 +1921,8 @@
|
||||
termState.toolsDir = env.TOOLS;
|
||||
termState.projectsDir = env.PROJECTS;
|
||||
termState.cwd = env.CWD || env.HOME;
|
||||
termState.hasProot = env.hasProot === true;
|
||||
termState.prootPath = env.prootPath || '';
|
||||
}
|
||||
|
||||
var prefix = termState.homeDir ? termState.homeDir.replace('/home', '') : termState.homeDir || '';
|
||||
@@ -1947,15 +1951,15 @@
|
||||
|
||||
var methods = [];
|
||||
if (pkgTest.exitCode === 0) {
|
||||
methods.push('chmod 755 "' + pkgBin + '" 2>/dev/null; "' + pkgBin + '" update -y 2>&1 && "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1');
|
||||
methods.push({cmd: 'export PREFIX="' + prefixUsr + '" PATH="' + prefixUsr + '/bin:$PATH" LD_LIBRARY_PATH="' + prefixUsr + '/lib" && sh "' + pkgBin + '" update -y 2>&1 && sh "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1', label: 'pkg'});
|
||||
}
|
||||
if (aptTest.exitCode === 0) {
|
||||
methods.push('chmod 755 "' + aptBin + '" 2>/dev/null; "' + aptBin + '" update -y 2>&1 && "' + aptBin + '" install -y aapt2 ecj dx apksigner 2>&1');
|
||||
methods.push({cmd: 'export PREFIX="' + prefixUsr + '" PATH="' + prefixUsr + '/bin:$PATH" LD_LIBRARY_PATH="' + prefixUsr + '/lib" && sh "' + aptBin + '" update -y 2>&1 && sh "' + aptBin + '" install -y aapt2 ecj dx apksigner 2>&1', label: 'apt'});
|
||||
}
|
||||
|
||||
for (var m = 0; m < methods.length; m++) {
|
||||
termPrint('[*] Attempt ' + (m + 1) + '...', 'info');
|
||||
var installResult = await shellExec(methods[m], termState.homeDir, false);
|
||||
termPrint('[*] Attempt ' + (m + 1) + ' (' + methods[m].label + ')...', 'info');
|
||||
var installResult = await shellExec(methods[m].cmd, termState.homeDir, false);
|
||||
if (installResult.output) {
|
||||
var out = installResult.output;
|
||||
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
|
||||
@@ -1971,12 +1975,58 @@
|
||||
}
|
||||
}
|
||||
|
||||
termPrint('[!] Auto-install failed. Open Terminal and run:', 'err');
|
||||
termPrint(' pkg update && pkg install aapt2 ecj dx apksigner', 'warning');
|
||||
termPrint('[*] Direct execution failed. Trying PRoot workaround...', 'info');
|
||||
var prootOk = await tryProotInstall(prefixUsr, pkgBin, aptBin);
|
||||
if (prootOk) return true;
|
||||
|
||||
termPrint('', '');
|
||||
termPrint('[!] Auto-install failed. Android SELinux may be blocking binary execution.', 'err');
|
||||
termPrint('[*] Fallback options:', 'warning');
|
||||
termPrint(' 1. Install Termux from F-Droid, then run:', 'warning');
|
||||
termPrint(' pkg install aapt2 ecj dx apksigner', 'warning');
|
||||
termPrint(' 2. Z.AI Chat will auto-detect Termux tools.', 'warning');
|
||||
termState.devToolsInstalled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
async function tryProotInstall(prefixUsr, pkgBin, aptBin) {
|
||||
try {
|
||||
termPrint('[*] Downloading PRoot from Termux repo...', 'info');
|
||||
var prootResult = await Bootstrap.installProot();
|
||||
if (!prootResult || !prootResult.path) {
|
||||
termPrint('[!] PRoot download failed', 'err');
|
||||
return false;
|
||||
}
|
||||
termPrint('[OK] PRoot downloaded: ' + prootResult.path, 'success');
|
||||
termState.hasProot = true;
|
||||
termState.prootPath = prootResult.path;
|
||||
} catch(e) {
|
||||
termPrint('[!] PRoot download failed: ' + e.message, 'err');
|
||||
return false;
|
||||
}
|
||||
|
||||
var prootCmd = termState.prootPath;
|
||||
var pkgCmd = 'sh "' + pkgBin + '" update -y 2>&1 && sh "' + pkgBin + '" install -y aapt2 ecj dx apksigner 2>&1';
|
||||
var wrappedCmd = prootCmd + ' -0 -b /dev -b /proc -b /sys -r ' + prefixUsr + ' /bin/sh -c \'' + pkgCmd.replace(/'/g, "'\\''") + '\'';
|
||||
|
||||
termPrint('[*] Installing via PRoot...', 'info');
|
||||
var result = await shellExec(wrappedCmd, termState.homeDir, false);
|
||||
if (result.output) {
|
||||
var out = result.output;
|
||||
if (out.length > 2000) out = out.substring(0, 1000) + '\n... truncated ...\n' + out.substring(out.length - 800);
|
||||
termPrint(out.replace(/\n$/, ''), '');
|
||||
}
|
||||
|
||||
var recheck = await shellExec('command -v aapt2 >/dev/null 2>&1 && command -v ecj >/dev/null 2>&1', termState.homeDir, false);
|
||||
if (recheck.exitCode === 0) {
|
||||
termPrint('[OK] Build tools installed via PRoot!', 'success');
|
||||
showStatusToast('Build tools installed!', 'success');
|
||||
termState.devToolsInstalled = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkDevEnvironment() {
|
||||
if (state.currentMode !== 'coding' && state.currentMode !== 'agentic') return;
|
||||
|
||||
@@ -2387,7 +2437,7 @@
|
||||
if (toolsStatus) {
|
||||
toolsStatus.innerHTML = toolsOk
|
||||
? '<span style="color:var(--success)">✔ All tools installed — ready to build!</span>'
|
||||
: '<span style="color:var(--warning)">Build tools not installed. Open Terminal and run: pkg install aapt2 ecj dx apksigner</span>';
|
||||
: '<span style="color:var(--warning)">Build tools not installed.<br>1. Install Termux from F-Droid<br>2. Run: pkg install aapt2 ecj dx apksigner<br>3. Z.AI Chat will auto-detect Termux tools.</span>';
|
||||
}
|
||||
|
||||
btn.querySelector('.btn-text').textContent = 'Installed';
|
||||
|
||||
Reference in New Issue
Block a user