这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
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
83 changes: 74 additions & 9 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ plugins {
}

android {
flavorDimensions "version"
productFlavors {
current {
dimension "version"
targetSdkVersion project.properties.targetSdkVersion.toInteger()
}
updated {
dimension "version"
targetSdkVersion project.properties.updatedTargetSdkVersion.toInteger()
}
}

compileSdkVersion project.properties.compileSdkVersion.toInteger()
ndkVersion project.properties.ndkVersion

Expand All @@ -25,7 +37,6 @@ android {
defaultConfig {
applicationId "com.termux"
minSdkVersion project.properties.minSdkVersion.toInteger()
targetSdkVersion project.properties.targetSdkVersion.toInteger()
versionCode 112
versionName "0.112"

Expand Down Expand Up @@ -104,11 +115,62 @@ task versionName {
}
}

def downloadBootstrap(String arch, String expectedChecksum, String version) {
def expandBootstrap(File bootstrapZip, String expectedChecksum, String arch) {
def doneMarkerFile = new File(bootstrapZip.getAbsolutePath() + "." + expectedChecksum + ".done")
if (doneMarkerFile.exists()) return

def archDirName
if (arch == "aarch64") archDirName = "arm64-v8a";
if (arch == "arm") archDirName = "armeabi-v7a";
if (arch == "i686") archDirName = "x86";
if (arch == "x86_64") archDirName = "x86_64";

def outputPath = project.getRootDir().getAbsolutePath() + "/app/src/main/jniLibs/" + archDirName + "/"
def outputDir = new File(outputPath).getAbsoluteFile()
if (!outputDir.exists()) outputDir.mkdirs()

def symlinksFile = new File(outputDir, "libsymlinks.so").getAbsoluteFile()
if (symlinksFile.exists()) symlinksFile.delete();

def mappingsFile = new File(outputDir, "libfiles.so").getAbsoluteFile()
if (mappingsFile.exists()) mappingsFile.delete()
mappingsFile.createNewFile()
def mappingsFileWriter = new BufferedWriter(new FileWriter(mappingsFile))

def counter = 100
new java.util.zip.ZipInputStream(new FileInputStream(bootstrapZip)).withCloseable { zipInput ->
def zipEntry
while ((zipEntry = zipInput.getNextEntry()) != null) {
if (zipEntry.getName() == "SYMLINKS.txt") {
zipInput.transferTo(new FileOutputStream(symlinksFile))
} else if (!zipEntry.isDirectory()) {
def soName = "lib" + counter + ".so"
def targetFile = new File(outputDir, soName).getAbsoluteFile()

println "target file path is ${targetFile}"

try {
zipInput.transferTo(new FileOutputStream(targetFile))
} catch (Exception e) {
println "Error ${e}"
}


mappingsFileWriter.writeLine(soName + "←" + zipEntry.getName())
counter++
}
}
}

mappingsFileWriter.close()
doneMarkerFile.createNewFile()
}

def downloadBootstrap(String arch, String expectedChecksum, String version, boolean isPackagesInApk) {
def digest = java.security.MessageDigest.getInstance("SHA-256")

def localUrl = "src/main/cpp/bootstrap-" + arch + ".zip"
def file = new File(projectDir, localUrl)
def file = isPackagesInApk ? new File(project.buildDir, "./gradle/bootstrap-" + arch + "-" + version + ".zip")
: new File(projectDir, "src/main/cpp/bootstrap-" + arch + ".zip");
if (file.exists()) {
def buffer = new byte[8192]
def input = new FileInputStream(file)
Expand All @@ -119,9 +181,10 @@ def downloadBootstrap(String arch, String expectedChecksum, String version) {
}
def checksum = new BigInteger(1, digest.digest()).toString(16)
if (checksum == expectedChecksum) {
if (isPackagesInApk) expandBootstrap(file, expectedChecksum, arch)
return
} else {
logger.quiet("Deleting old local file with wrong hash: " + localUrl)
logger.quiet("Deleting old local file with wrong hash: " + file)
file.delete()
}
}
Expand All @@ -143,6 +206,7 @@ def downloadBootstrap(String arch, String expectedChecksum, String version) {
file.delete()
throw new GradleException("Wrong checksum for " + remoteUrl + ": expected: " + expectedChecksum + ", actual: " + checksum)
}
if (isPackagesInApk) expandBootstrap(file, expectedChecksum, arch)
}

clean {
Expand All @@ -154,12 +218,13 @@ clean {
}

task downloadBootstraps() {
boolean isPackagesInApk = getGradle().getStartParameter().getTaskRequests().toString().contains("Updated");
doLast {
def version = "2021.04.13-r1"
downloadBootstrap("aarch64", "ff82e5755d947cd1f3e0b30916d125c6ddd8ba3254801ca7499d73653417e158", version)
downloadBootstrap("arm", "53a7df2d6d0a36a8c9ab5259c8b5457c93b8bae8aec2321a470236b6da54e59a", version)
downloadBootstrap("i686", "f0e1399a13ebed6c5229fde161f9848d9f5eeae7b8cd82f31250a813b52e371", version)
downloadBootstrap("x86_64", "e36c4d8c933dc12b3f48937b7747c7a4dcfaa70f0dd89ad5e8b4465930075ae9", version)
downloadBootstrap("aarch64", "ff82e5755d947cd1f3e0b30916d125c6ddd8ba3254801ca7499d73653417e158", version, isPackagesInApk)
downloadBootstrap("arm", "53a7df2d6d0a36a8c9ab5259c8b5457c93b8bae8aec2321a470236b6da54e59a", version, isPackagesInApk)
downloadBootstrap("i686", "f0e1399a13ebed6c5229fde161f9848d9f5eeae7b8cd82f31250a813b52e371", version, isPackagesInApk)
downloadBootstrap("x86_64", "e36c4d8c933dc12b3f48937b7747c7a4dcfaa70f0dd89ad5e8b4465930075ae9", version, isPackagesInApk)
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/termux/app/TermuxInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public void run() {
}.start();
}

private static void ensureDirectoryExists(Context context, File directory) {
public static void ensureDirectoryExists(Context context, File directory) {
String errmsg;

errmsg = FileUtils.createDirectoryFile(context, directory.getAbsolutePath());
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/termux/app/TermuxService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.app.PendingIntent;
import android.app.Service;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
Expand Down Expand Up @@ -112,6 +113,12 @@ class LocalBinder extends Binder {
public void onCreate() {
Logger.logVerbose(LOG_TAG, "onCreate");
runStartForeground();

if (getApplicationContext().getApplicationInfo().targetSdkVersion >= 30) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.termux","com.termux.app.TermuxPackageInstallerService"));
startService(intent);
}
}

@SuppressLint("Wakelock")
Expand Down
19 changes: 19 additions & 0 deletions app/src/updated/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.termux">

<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />

<application>
<service
android:name=".app.TermuxPackageInstallerService"
android:exported="false" />
</application>

</manifest>
138 changes: 138 additions & 0 deletions app/src/updated/java/com/termux/app/TermuxPackageInstaller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.termux.app;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Process;
import android.system.Os;
import android.util.Log;

import com.termux.shared.termux.TermuxConstants;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class TermuxPackageInstaller extends BroadcastReceiver {

private static final String LOG_TAG = "termux-package-installer";


@Override
public void onReceive(Context context, Intent intent) {
try {
String packageName = intent.getData().getSchemeSpecificPart();
String action = intent.getAction();
PackageManager packageManager = context.getPackageManager();

if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
ApplicationInfo info = packageManager.getApplicationInfo(packageName, 0);
if (Process.myUid() == info.uid) {
installPackage(context, info);
}
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
if (Process.myUid() == intent.getIntExtra(Intent.EXTRA_UID, -1)) {
uninstallPackage(packageName);
}

}
} catch (Exception e) {
Log.e("termux", "Error in package management: " + e);
}
}

static void installPackage(Context context, ApplicationInfo info) throws Exception {
File filesMappingFile = new File(info.nativeLibraryDir, "libfiles.so");
if (!filesMappingFile.exists()) {
Log.e("termux", "No file mapping at " + filesMappingFile.getAbsolutePath());
return;
}

Log.e("termux", "Installing: " + info.packageName);
BufferedReader reader = new BufferedReader(new FileReader(filesMappingFile));
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("←");
if (parts.length != 2) {
Log.e(LOG_TAG, "Malformed line " + line + " in " + filesMappingFile.getAbsolutePath());
continue;
}

String oldPath = info.nativeLibraryDir + "/" + parts[0];
String newPath = TermuxConstants.TERMUX_PREFIX_DIR_PATH + "/" + parts[1];

TermuxInstaller.ensureDirectoryExists(context, new File(newPath).getParentFile());

Log.e(LOG_TAG, "About to setup link: " + oldPath + " ← " + newPath);
new File(newPath).delete();
Os.symlink(oldPath, newPath);
}

File symlinksFile = new File(info.nativeLibraryDir, "libsymlinks.so");
if (!symlinksFile.exists()) {
Log.e("termux", "No symlinks mapping at " + symlinksFile.getAbsolutePath());
}

reader = new BufferedReader(new FileReader(symlinksFile));
while ((line = reader.readLine()) != null) {
String[] parts = line.split("←");
if (parts.length != 2) {
Log.e(LOG_TAG, "Malformed line " + line + " in " + symlinksFile.getAbsolutePath());
continue;
}

String oldPath = parts[0];
String newPath = TermuxConstants.TERMUX_PREFIX_DIR_PATH + "/" + parts[1];

TermuxInstaller.ensureDirectoryExists(context, new File(newPath).getParentFile());

Log.e(LOG_TAG, "About to setup link: " + oldPath + " ← " + newPath);
new File(newPath).delete();
Os.symlink(oldPath, newPath);
}
}

private static void uninstallPackage(String packageName) throws IOException {
Log.e(LOG_TAG, "Uninstalling: " + packageName);
// We're currently visiting the whole $PREFIX.
// If we store installed symlinks in installPackage() we could just visit those,
// at the cost of increased complexity and risk for errors.
File prefixDir = new File(TermuxConstants.TERMUX_PREFIX_DIR_PATH);
removeBrokenSymlinks(prefixDir);
}

private static void removeBrokenSymlinks(File parentDir) throws IOException {
File[] children = parentDir.listFiles();
if (children == null) {
return;
}
for (File child : children) {
if (!child.exists()) {
Log.e(LOG_TAG, "Removing broken symlink: " + child.getAbsolutePath());
child.delete();
} else if (child.isDirectory()) {
removeBrokenSymlinks(child);
}
}
}

public static void setupAllInstalledPackages(Context context) {
try {
removeBrokenSymlinks(new File(TermuxConstants.TERMUX_PREFIX_DIR_PATH));

PackageManager packageManager = context.getPackageManager();
for (PackageInfo info : packageManager.getInstalledPackages(0)) {
if ("com.termux".equals(info.sharedUserId)) {
installPackage(context, info.applicationInfo);
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "Error setting up all packages", e);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.termux.app;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.system.Os;
import android.util.Log;

import androidx.annotation.Nullable;

import com.termux.shared.termux.TermuxConstants;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class TermuxPackageInstallerService extends Service {

private static final String LOG_TAG = "termux-package-installer";

class LocalBinder extends Binder {
public final TermuxPackageInstallerService service = TermuxPackageInstallerService.this;
}

private final IBinder mBinder = new LocalBinder();

@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

@Override
public void onCreate() {
super.onCreate();

TermuxPackageInstaller packageInstaller = new TermuxPackageInstaller();
TermuxPackageInstaller.setupAllInstalledPackages(this);

IntentFilter addedFilter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
addedFilter.addDataScheme("package");
IntentFilter removedFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
removedFilter.addDataScheme("package");
this.registerReceiver(packageInstaller, addedFilter);
this.registerReceiver(packageInstaller, removedFilter);
}
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ termuxVersionCode=111

minSdkVersion=24
targetSdkVersion=28
updatedTargetSdkVersion=30
ndkVersion=22.1.7171670
compileSdkVersion=30

Expand Down