Files
NeoTerm_System/app/src/main/java/io/neoterm/installer/BaseFileInstaller.java

170 lines
7.2 KiB
Java
Raw Normal View History

2017-06-13 18:07:14 +08:00
package io.neoterm.installer;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Build;
import android.system.Os;
import android.util.Log;
import android.util.Pair;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import io.neoterm.backend.EmulatorDebug;
2017-06-15 12:52:14 +08:00
import io.neoterm.customize.NeoTermPath;
2017-06-13 18:07:14 +08:00
import io.neoterm.preference.NeoTermPreference;
public final class BaseFileInstaller {
2017-06-15 12:52:14 +08:00
public interface ResultListener {
void onResult(Exception error);
}
2017-06-13 18:07:14 +08:00
public static void installBaseFiles(final Activity activity, final ResultListener resultListener) {
2017-06-15 12:52:14 +08:00
final File PREFIX_FILE = new File(NeoTermPath.USR_PATH);
2017-06-13 18:07:14 +08:00
if (PREFIX_FILE.isDirectory()) {
resultListener.onResult(null);
2017-06-13 18:07:14 +08:00
return;
}
final ProgressDialog progress = ProgressDialog.show(activity, null, "Installing", true, false);
new Thread() {
@Override
public void run() {
try {
2017-06-15 12:52:14 +08:00
final String STAGING_PREFIX_PATH = NeoTermPath.ROOT_PATH + "/usr-staging";
2017-06-13 18:07:14 +08:00
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
if (STAGING_PREFIX_FILE.exists()) {
deleteFolder(STAGING_PREFIX_FILE);
}
final byte[] buffer = new byte[8096];
final List<Pair<String, String>> symlinks = new ArrayList<>(50);
final URL zipUrl = determineZipUrl();
try (ZipInputStream zipInput = new ZipInputStream(zipUrl.openStream())) {
ZipEntry zipEntry;
while ((zipEntry = zipInput.getNextEntry()) != null) {
if (zipEntry.getName().equals("SYMLINKS.txt")) {
BufferedReader symlinksReader = new BufferedReader(new InputStreamReader(zipInput));
String line;
while ((line = symlinksReader.readLine()) != null) {
if (line.isEmpty()) {
continue;
}
String[] parts = line.split("");
if (parts.length != 2)
throw new RuntimeException("Malformed symlink line: " + line);
String oldPath = parts[0];
String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
symlinks.add(Pair.create(oldPath, newPath));
}
} else {
String zipEntryName = zipEntry.getName();
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
if (zipEntry.isDirectory()) {
if (!targetFile.mkdirs())
throw new RuntimeException("Failed to create directory: " + targetFile.getAbsolutePath());
} else {
try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
int readBytes;
while ((readBytes = zipInput.read(buffer)) != -1)
outStream.write(buffer, 0, readBytes);
}
if (zipEntryName.startsWith("bin/") || zipEntryName.startsWith("libexec") || zipEntryName.startsWith("lib/apt/methods")) {
//noinspection OctalInteger
Os.chmod(targetFile.getAbsolutePath(), 0700);
}
}
}
}
}
if (symlinks.isEmpty())
throw new RuntimeException("No SYMLINKS.txt encountered");
for (Pair<String, String> symlink : symlinks) {
Os.symlink(symlink.first, symlink.second);
}
if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) {
throw new RuntimeException("Unable to rename staging folder");
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
resultListener.onResult(null);
2017-06-13 18:07:14 +08:00
}
});
} catch (final Exception e) {
Log.e(EmulatorDebug.LOG_TAG, "Bootstrap error", e);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
resultListener.onResult(e);
} catch (RuntimeException e) {
2017-06-13 18:07:14 +08:00
// Activity already dismissed - ignore.
}
}
});
} finally {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
progress.dismiss();
} catch (RuntimeException e) {
// Activity already dismissed - ignore.
}
}
});
}
}
}.start();
}
private static URL determineZipUrl() throws MalformedURLException {
String archName = determineArchName();
return new URL("https://kernel19.cc/neoterm/boot/" + archName + ".zip");
}
public static String determineArchName() {
2017-06-13 18:07:14 +08:00
for (String androidArch : Build.SUPPORTED_ABIS) {
switch (androidArch) {
case "arm64-v8a":
return "aarch64";
case "armeabi-v7a":
return "arm";
case "x86_64":
return "x86_64";
case "x86":
return "i686";
}
}
throw new RuntimeException("Unable to determine arch from Build.SUPPORTED_ABIS = " +
Arrays.toString(Build.SUPPORTED_ABIS));
}
private static void deleteFolder(File fileOrDirectory) {
File[] children = fileOrDirectory.listFiles();
if (children != null) {
for (File child : children) {
deleteFolder(child);
}
}
if (!fileOrDirectory.delete()) {
throw new RuntimeException("Unable to delete " + (fileOrDirectory.isDirectory() ? "directory " : "file ") + fileOrDirectory.getAbsolutePath());
}
}
}