Files
NeoTerm_System/app/src/main/java/io/neoterm/setup/SetupThread.java

166 lines
6.5 KiB
Java
Raw Normal View History

2017-12-20 23:49:53 +08:00
package io.neoterm.setup;
2017-12-16 16:59:59 +08:00
import android.app.ProgressDialog;
import androidx.appcompat.app.AppCompatActivity;
2017-12-16 16:59:59 +08:00
import android.system.Os;
import android.util.Pair;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
2018-07-31 22:31:43 +08:00
import java.io.IOException;
2017-12-16 16:59:59 +08:00
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import io.neoterm.backend.EmulatorDebug;
import io.neoterm.frontend.config.NeoTermPath;
import io.neoterm.frontend.logging.NLog;
/**
* @author kiva
*/
final class SetupThread extends Thread {
private final SourceConnection sourceConnection;
private final File prefixPath;
private final AppCompatActivity activity;
2017-12-16 16:59:59 +08:00
private final ResultListener resultListener;
private final ProgressDialog progressDialog;
public SetupThread(AppCompatActivity activity, SourceConnection sourceConnection,
2017-12-16 16:59:59 +08:00
File prefixPath, ResultListener resultListener,
ProgressDialog progressDialog) {
this.activity = activity;
this.sourceConnection = sourceConnection;
this.prefixPath = prefixPath;
this.resultListener = resultListener;
this.progressDialog = progressDialog;
}
@Override
public void run() {
try {
final String stagingPrefixPath = NeoTermPath.ROOT_PATH + "/usr-staging";
final File stagingPrefixFile = new File(stagingPrefixPath);
if (stagingPrefixFile.exists()) {
deleteFolder(stagingPrefixFile);
}
int totalReadBytes = 0;
final byte[] buffer = new byte[8096];
final List<Pair<String, String>> symlinks = new ArrayList<>(50);
try (ZipInputStream zipInput = new ZipInputStream(sourceConnection.getInputStream())) {
ZipEntry zipEntry;
int totalBytes = sourceConnection.getSize();
2017-12-16 16:59:59 +08:00
while ((zipEntry = zipInput.getNextEntry()) != null) {
totalReadBytes += zipEntry.getCompressedSize();
final int totalReadBytesFinal = totalReadBytes;
final int totalBytesFinal = totalBytes;
2018-03-25 00:39:46 +08:00
activity.runOnUiThread(() -> {
try {
double progressFloat = ((double) totalReadBytesFinal) / ((double) totalBytesFinal) * 100.0;
progressDialog.setProgress((int) progressFloat);
} catch (RuntimeException ignore) {
// activity dismissed
2017-12-16 16:59:59 +08:00
}
});
if (zipEntry.getName().contains("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 = stagingPrefixPath + "/" + parts[1];
symlinks.add(Pair.create(oldPath, newPath));
}
} else {
String zipEntryName = zipEntry.getName();
File targetFile = new File(stagingPrefixPath, 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);
}
}
}
}
}
sourceConnection.close();
if (symlinks.isEmpty())
throw new RuntimeException("No SYMLINKS.txt encountered");
for (Pair<String, String> symlink : symlinks) {
NLog.INSTANCE.e("Setup", "Linking " + symlink.first + " to " + symlink.second);
Os.symlink(symlink.first, symlink.second);
}
if (!stagingPrefixFile.renameTo(prefixPath)) {
throw new RuntimeException("Unable to rename staging folder");
}
2018-07-31 22:31:43 +08:00
activity.runOnUiThread(() -> resultListener.onResult(null));
2017-12-16 16:59:59 +08:00
} catch (final Exception e) {
NLog.INSTANCE.e(EmulatorDebug.LOG_TAG, "Bootstrap error", e);
2018-07-31 22:31:43 +08:00
activity.runOnUiThread(() -> {
try {
resultListener.onResult(e);
} catch (RuntimeException e1) {
// Activity already dismissed - ignore.
2017-12-16 16:59:59 +08:00
}
});
} finally {
2018-07-31 22:31:43 +08:00
activity.runOnUiThread(() -> {
try {
progressDialog.dismiss();
} catch (RuntimeException e) {
// Activity already dismissed - ignore.
2017-12-16 16:59:59 +08:00
}
});
}
}
2018-07-31 22:31:43 +08:00
private static void deleteFolder(File fileOrDirectory) throws IOException {
if (fileOrDirectory.getCanonicalPath().equals(fileOrDirectory.getAbsolutePath()) && fileOrDirectory.isDirectory()) {
File[] children = fileOrDirectory.listFiles();
if (children != null) {
for (File child : children) {
deleteFolder(child);
}
2017-12-16 16:59:59 +08:00
}
}
2018-07-31 22:31:43 +08:00
2017-12-16 16:59:59 +08:00
if (!fileOrDirectory.delete()) {
2018-07-31 22:31:43 +08:00
throw new RuntimeException("Unable to delete "
+ (fileOrDirectory.isDirectory() ? "directory " : "file ")
+ fileOrDirectory.getAbsolutePath());
2017-12-16 16:59:59 +08:00
}
}
}