diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
index 64f9316..5a9496c 100644
--- a/.idea/dbnavigator.xml
+++ b/.idea/dbnavigator.xml
@@ -4,14 +4,155 @@
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -426,4 +567,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/MainActivity.kt b/app/src/main/java/com/android/grape/MainActivity.kt
index 96f0bad..bd01445 100644
--- a/app/src/main/java/com/android/grape/MainActivity.kt
+++ b/app/src/main/java/com/android/grape/MainActivity.kt
@@ -18,6 +18,7 @@ import com.android.grape.util.MockTools
import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.ScriptUtils.registerScriptResultReceiver
import com.android.grape.util.ScriptUtils.unregisterScriptResultReceiver
+import com.android.grape.util.ShellUtil
import com.android.grape.util.StoragePermissionHelper
/**
diff --git a/app/src/main/java/com/android/grape/data/Device.kt b/app/src/main/java/com/android/grape/data/Device.kt
index ef19955..3d084a4 100644
--- a/app/src/main/java/com/android/grape/data/Device.kt
+++ b/app/src/main/java/com/android/grape/data/Device.kt
@@ -75,8 +75,8 @@ data class Device(
var nativeDir: Boolean = false,
var network: String = "",
var noRcLatency: Boolean = false,
- @SerializedName("open_referrer")
- var openReferrer: String = "",
+// @SerializedName("open_referrer")//todo string or object
+// var openReferrer: String = "",
@SerializedName("open_referrerReset")
var openReferrerReset: Int = 0,
var opener: String = "",
diff --git a/app/src/main/java/com/android/grape/sai/ShellSaiPackageInstaller.kt b/app/src/main/java/com/android/grape/sai/ShellSaiPackageInstaller.kt
index a1c8651..5bf328e 100644
--- a/app/src/main/java/com/android/grape/sai/ShellSaiPackageInstaller.kt
+++ b/app/src/main/java/com/android/grape/sai/ShellSaiPackageInstaller.kt
@@ -23,6 +23,7 @@ import com.android.grape.sai.prefers.PreferencesHelper
import com.android.grape.sai.rootless.AndroidPackageInstallerError
import com.android.grape.sai.shell.MiuiUtils
import com.android.grape.sai.shell.Shell
+import com.android.grape.util.FileUtils
import com.android.grape.util.TaskUtils
import com.android.grape.util.TaskUtils.setInstallRet
import com.blankj.utilcode.util.LogUtils
@@ -137,7 +138,7 @@ abstract class ShellSaiPackageInstaller protected constructor(c: Context?) :
}
androidSessionId = createSession()
//todo params.apkSource().apkLocalPath?
- val path = "/sdcard/apks/${recordPackageName}"
+ val path = "${FileUtils.CACHE_PATH}${recordPackageName}"
val file = File(path)
val files = file.listFiles()
diff --git a/app/src/main/java/com/android/grape/util/AppUtils.kt b/app/src/main/java/com/android/grape/util/AppUtils.kt
index e796f75..1619a7a 100644
--- a/app/src/main/java/com/android/grape/util/AppUtils.kt
+++ b/app/src/main/java/com/android/grape/util/AppUtils.kt
@@ -610,7 +610,7 @@ object AppUtils {
) {
true
} else {
- downloadFile(url, "/sdcard/apks/$recordFileName")
+ downloadFile(url, "${FileUtils.CACHE_PATH}$recordFileName")
}
if (ret) {
diff --git a/app/src/main/java/com/android/grape/util/BackupUtils.kt b/app/src/main/java/com/android/grape/util/BackupUtils.kt
index 1000ca0..b746936 100644
--- a/app/src/main/java/com/android/grape/util/BackupUtils.kt
+++ b/app/src/main/java/com/android/grape/util/BackupUtils.kt
@@ -127,11 +127,11 @@ object BackupUtils {
*/
fun killRecordProcess(context: Context?, packageName: String?) {
Log.i("BackupUtils", "start killRecordProcess :$packageName")
-
try {
val cmd = "am force-stop $packageName"
Log.i("BackupUtils", "killRecordProcess-> cmd:$cmd")
- MockTools.exec(cmd)
+ ShellUtil.execRootCmdAndGetResult(cmd)
+// MockTools.exec(cmd)
} catch (e: Exception) {
e.printStackTrace()
}
diff --git a/app/src/main/java/com/android/grape/util/DeviceUtils.kt b/app/src/main/java/com/android/grape/util/DeviceUtils.kt
index f6d5c26..2bb1939 100644
--- a/app/src/main/java/com/android/grape/util/DeviceUtils.kt
+++ b/app/src/main/java/com/android/grape/util/DeviceUtils.kt
@@ -71,11 +71,56 @@ object DeviceUtils {
* @param context
* @return
*/
- fun getUserAndGroupSh(context: Context, packageName: String?, string: String): String {
- return getUserAndGroupSh(
- context,
- recordPackageName, getRecordTxtFileName(context)
- )
+ fun getUserAndGroupSh(context: Context, packageName: String?, txtFileName: String): String {
+ try {
+// String txtFileName = getRecordTxtFileName(context);
+
+ val cmd = "ls /data/data -l | grep $packageName"
+ val result = MockTools.execRead(cmd)
+
+ val txtFile = File(txtFileName)
+
+ if (result.length > 20) {
+ val contents = result
+ Log.i(
+ TAG,
+ "getUserAndGroupSh file->$txtFileName; contents:$contents"
+ )
+ if (contents.length > 0) {
+ val arr =
+ contents.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ var userAndGroup = ""
+ for (i in arr.indices) {
+ val line = arr[i]
+ Log.i(
+ TAG,
+ "getUserAndGroup: line=$line"
+ )
+
+ if (line.endsWith(" $packageName")) {
+ val arr1 = line.split(" ".toRegex()).dropLastWhile { it.isEmpty() }
+ .toTypedArray()
+ for (s1 in arr1) {
+ if (s1.startsWith("u0_")) {
+ val user = s1
+ userAndGroup = "$user:$user"
+ Log.i(
+ TAG,
+ "getUserAndGroupSh userAndGroup:$userAndGroup"
+ )
+ break
+ }
+ }
+ }
+ }
+ return userAndGroup
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ return ""
}
/**
diff --git a/app/src/main/java/com/android/grape/util/FileUtils.kt b/app/src/main/java/com/android/grape/util/FileUtils.kt
index 7fe0d1d..88df888 100644
--- a/app/src/main/java/com/android/grape/util/FileUtils.kt
+++ b/app/src/main/java/com/android/grape/util/FileUtils.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.os.Environment
import android.util.Base64
import android.util.Log
+import com.android.grape.MainApplication
import com.android.grape.data.AppState.apkDir
import com.android.grape.data.AppState.monitorDir
import com.android.grape.data.AppState.recordFileName
@@ -43,6 +44,7 @@ object FileUtils {
public const val BUFFER_SIZE = 1024 * 1024 //1M Byte
public var name: String? = null
+ val CACHE_PATH = "${MainApplication.instance.cacheDir.absolutePath}/"
fun delFiles(context: Context?) {
Log.i("TaskUtils", "start to delFiles : " + startInstallTime)
@@ -68,7 +70,7 @@ object FileUtils {
}
public fun getRecordSdcardApkVerFileName(context: Context): String {
- return "/sdcard/apks/" + recordFileName
+ return "${FileUtils.CACHE_PATH}" + recordFileName
}
public fun forceCreteDir(file: File) {
diff --git a/app/src/main/java/com/android/grape/util/MockTools.kt b/app/src/main/java/com/android/grape/util/MockTools.kt
index c32b254..6bd8b4e 100644
--- a/app/src/main/java/com/android/grape/util/MockTools.kt
+++ b/app/src/main/java/com/android/grape/util/MockTools.kt
@@ -12,7 +12,7 @@ object MockTools {
fun exec(cmd: String): String {
var retString = ""
try {
- retString = ShellUtils.execRootCmdAndGetResult(cmd)
+ retString = ShellUtil.execRootCmdAndGetResult(cmd)
// //创建socket
// val myCmd = "SU|$cmd"
//
@@ -41,7 +41,7 @@ object MockTools {
fun execRead(cmd: String): String {
var retString = ""
try {
- retString = ShellUtils.execRootCmdAndGetResult(cmd)
+ retString = ShellUtil.execRootCmdAndGetResult(cmd)
// //创建socket
// val myCmd = "SU_1|$cmd"
//
diff --git a/app/src/main/java/com/android/grape/util/ScriptUtils.kt b/app/src/main/java/com/android/grape/util/ScriptUtils.kt
index 89674de..59a54e6 100644
--- a/app/src/main/java/com/android/grape/util/ScriptUtils.kt
+++ b/app/src/main/java/com/android/grape/util/ScriptUtils.kt
@@ -18,6 +18,7 @@ import com.android.grape.net.AfClient.downloadFile
import com.android.grape.receiver.ScriptReceiver
import com.android.grape.util.ShellUtils.delFileSh
import com.android.grape.util.ShellUtils.unzipAPkSh
+import com.android.grape.util.ShellUtils.unzipScriptSh
import com.blankj.utilcode.util.LogUtils
/**
@@ -52,7 +53,7 @@ object ScriptUtils {
Log.i("TaskUtils", "execDownScript isDownload : $isDownload")
return false
}
- unzipAPkSh(script_path, "/sdcard/script/")
+ unzipScriptSh(script_path, "/sdcard/script/")
delFileSh(script_path)
}
return isDownload
diff --git a/app/src/main/java/com/android/grape/util/ShellUtil.java b/app/src/main/java/com/android/grape/util/ShellUtil.java
new file mode 100644
index 0000000..587224f
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/ShellUtil.java
@@ -0,0 +1,380 @@
+package com.android.grape.util;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.util.Log;
+
+import com.blankj.utilcode.util.LogUtils;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class ShellUtil {
+
+ public static String getPackagePath(Context context, String packageName) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
+ return appInfo.sourceDir; // 返回 APK 的完整路径
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ public static void exec(String cmd) {
+ try {
+ LogUtils.d(Log.INFO, "ShellUtils", "Executing command: " + cmd, null);
+ Process process = Runtime.getRuntime().exec(cmd);
+ process.waitFor();
+ } catch (Exception e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error executing command: " + e.getMessage(), e);
+ }
+ }
+
+ public static int getPid(Process p) {
+ int pid = -1;
+ try {
+ Field f = p.getClass().getDeclaredField("pid");
+ f.setAccessible(true);
+ pid = f.getInt(p);
+ f.setAccessible(false);
+ } catch (Throwable e) {
+ pid = -1;
+ }
+ return pid;
+ }
+
+ public static boolean hasBin(String binName) {
+ // 验证 binName 是否符合规则
+ if (binName == null || binName.isEmpty()) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Invalid bin name",null);
+ throw new IllegalArgumentException("Bin name cannot be null or empty");
+ }
+
+ for (char c : binName.toCharArray()) {
+ if (!Character.isLetterOrDigit(c) && c != '.' && c != '_' && c != '-') {
+ throw new IllegalArgumentException("Invalid bin name");
+ }
+ }
+
+ // 获取 PATH 环境变量
+ String pathEnv = System.getenv("PATH");
+ if (pathEnv == null) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "PATH environment variable is not available", null);
+ return false;
+ }
+
+ // 使用适合当前系统的路径分隔符分割路径
+ String[] paths = pathEnv.split(File.pathSeparator);
+ for (String path : paths) {
+ File file = new File(path, binName); // 使用 File 构造完整路径
+ try {
+ // 检查文件是否可执行
+ if (file.canExecute()) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Security exception occurred while checking: " + file.getAbsolutePath(), e);
+ }
+ }
+
+ // 如果未找到可执行文件,返回 false
+ return false;
+ }
+
+ public static String execRootCmdAndGetResult(String cmd) {
+ Log.d("ShellUtils", "execRootCmdAndGetResult - Started execution for command: " + cmd);
+ if (cmd == null || cmd.trim().isEmpty()) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Unsafe or empty command. Aborting execution.", null);
+ throw new IllegalArgumentException("Unsafe or empty command.");
+ }
+ // if (!isCommandSafe(cmd)) { // 检查命令的合法性
+ // Log.e("ShellUtils", "Detected unsafe command. Aborting execution.");
+ // throw new IllegalArgumentException("Detected unsafe command.");
+ // }
+
+ Process process = null;
+ ExecutorService executor = Executors.newFixedThreadPool(2);
+
+ try {
+ Log.d("ShellUtils", "Determining appropriate shell for execution...");
+// if (hasBin("su")) {
+// Log.d("ShellUtils", "'su' binary found, using 'su' shell.");
+// process = Runtime.getRuntime().exec("su");
+// } else if (hasBin("xu")) {
+// Log.d("ShellUtils", "'xu' binary found, using 'xu' shell.");
+// process = Runtime.getRuntime().exec("xu");
+// } else if (hasBin("vu")) {
+// Log.d("ShellUtils", "'vu' binary found, using 'vu' shell.");
+// process = Runtime.getRuntime().exec("vu");
+// } else {
+// Log.d("ShellUtils", "No specific binary found, using 'sh' shell.");
+// process = Runtime.getRuntime().exec("sh");
+// }
+ process = Runtime.getRuntime().exec("vu");
+
+ try (OutputStream os = new BufferedOutputStream(process.getOutputStream());
+ InputStream is = process.getInputStream();
+ InputStream errorStream = process.getErrorStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8))) {
+
+ Log.d("ShellUtils", "Starting separate thread to process error stream...");
+ executor.submit(() -> {
+ String line;
+ try {
+ while ((line = errorReader.readLine()) != null) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Shell Error: " + line, null);
+ }
+ } catch (IOException e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error while reading process error stream: " + e.getMessage(), e);
+ }
+ });
+
+ Log.d("ShellUtils", "Writing the command to the shell...");
+ os.write((cmd + "\n").getBytes());
+ os.write("exit\n".getBytes());
+ os.flush();
+ Log.d("ShellUtils", "Command written to shell. Waiting for process to complete.");
+
+ StringBuilder output = new StringBuilder();
+ String line;
+ while ((line = br.readLine()) != null) {
+ Log.d("ShellUtils", "Shell Output: " + line);
+ output.append(line).append("\n");
+ }
+
+ Log.d("ShellUtils", "Awaiting process termination...");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (!process.waitFor(10, TimeUnit.SECONDS)) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Process execution timed out. Destroying process.", null);
+ process.destroyForcibly();
+ throw new RuntimeException("Shell command execution timeout.");
+ }
+ } else {
+ Log.d("ShellUtils", "Using manual time tracking method for process termination (API < 26).");
+ long startTime = System.currentTimeMillis();
+ while (true) {
+ try {
+ process.exitValue();
+ break;
+ } catch (IllegalThreadStateException e) {
+ if (System.currentTimeMillis() - startTime > 10000) { // 10 seconds
+ LogUtils.d(Log.ERROR, "ShellUtils", "Process execution timed out (manual tracking). Destroying process.", null);
+ process.destroy();
+ throw new RuntimeException("Shell command execution timeout.");
+ }
+ Thread.sleep(100); // Sleep briefly before re-checking
+ }
+ }
+ }
+
+ Log.d("ShellUtils", "Process terminated successfully. Returning result.");
+ return output.toString().trim();
+ }
+ } catch (IOException | InterruptedException e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Command execution failed: " + e.getMessage(), e);
+ Thread.currentThread().interrupt();
+ return "Error: " + e.getMessage();
+ } finally {
+ if (process != null) {
+ Log.d("ShellUtils", "Finalizing process. Attempting to destroy it.");
+ process.destroy();
+ }
+ executor.shutdown();
+ Log.d("ShellUtils", "Executor service shut down.");
+ }
+ }
+
+ public static void execRootCmd(String cmd) {
+ // 校验命令是否安全
+ if (!isCommandSafe(cmd)) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Unsafe command, aborting.", null);
+ return;
+ }
+ List cmds = new ArrayList<>();
+ cmds.add(cmd);
+
+ // 使用同步锁保护线程安全
+ synchronized (ShellUtils.class) {
+ try {
+ List results = execRootCmds(cmds);
+ // 判断是否需要打印输出,仅用于开发调试阶段
+ for (String result : results) {
+ Log.d("ShellUtils", "Command Result: " + result);
+ }
+ } catch (Exception e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Unexpected error: " + e.getMessage(), e);
+ }
+ }
+ }
+
+
+ private static boolean isCommandSafe(String cmd) {
+ // 检查空值和空字符串
+ if (cmd == null || cmd.trim().isEmpty()) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Rejected command: empty or null value.", null);
+ return false;
+ }
+
+ // 检查非法字符
+ if (!cmd.matches("^[a-zA-Z0-9._/:\\-~`'\" *|]+$")) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Rejected command due to illegal characters: " + cmd, null);
+ return false;
+ }
+
+ // 检查多命令(逻辑运算符限制)
+ if (cmd.contains("&&") || cmd.contains("||")) {
+ Log.d("ShellUtils", "Command contains logical operators.");
+ if (!isExpectedMultiCommand(cmd)) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Rejected command due to prohibited structure: " + cmd, null);
+ return false;
+ }
+ }
+
+ // 路径遍历保护
+ if (cmd.contains("../") || cmd.contains("..\\")) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Rejected command due to path traversal attempt: " + cmd, null);
+ return false;
+ }
+
+ // 命令长度限制
+ if (cmd.startsWith("tar") && cmd.length() > 800) { // 特定命令支持更长长度
+ LogUtils.d(Log.ERROR, "ShellUtils", "Command rejected due to excessive length.", null);
+ return false;
+ } else if (cmd.length() > 500) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Command rejected due to excessive length.", null);
+ return false;
+ }
+
+ Log.d("ShellUtils", "Command passed safety checks: " + cmd);
+ return true;
+ }
+
+ // 附加方法:检查多命令是否符合预期
+ private static boolean isExpectedMultiCommand(String cmd) {
+ // 判断是否为允许的命令组合,比如 `cd` 或 `tar` 组合命令
+ return cmd.matches("^cd .+ && (tar|zip|cp).+");
+ }
+
+ public static List execRootCmds(List cmds) {
+ List results = new ArrayList<>();
+ Process process = null;
+ try {
+ // 初始化 Shell 环境
+ process = hasBin("su") ? Runtime.getRuntime().exec("su") : Runtime.getRuntime().exec("sh");
+
+ // 启动读取线程
+ Process stdProcess = process;
+ Thread stdThread = new Thread(() -> {
+ try (BufferedReader stdReader = new BufferedReader(new InputStreamReader(stdProcess.getInputStream()))) {
+ List localResults = new ArrayList<>();
+ String line;
+ while ((line = stdReader.readLine()) != null) {
+ localResults.add(line);
+ Log.d("ShellUtils", "Stdout: " + line);
+ }
+ synchronized (results) {
+ results.addAll(localResults);
+ }
+ } catch (IOException ioException) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error reading stdout", ioException);
+ }
+ });
+
+ Process finalProcess = process;
+ Thread errThread = new Thread(() -> {
+ try (BufferedReader errReader = new BufferedReader(new InputStreamReader(finalProcess.getErrorStream()))) {
+ String line;
+ while ((line = errReader.readLine()) != null) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Stderr: " + line, null);
+ }
+ } catch (IOException ioException) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error reading stderr", ioException);
+ }
+ });
+
+ // 启动子线程
+ stdThread.start();
+ errThread.start();
+
+ try (OutputStream os = process.getOutputStream()) {
+ for (String cmd : cmds) {
+// if (!isCommandSafe(cmd)) {
+// Log.w("ShellUtils", "Skipping unsafe command: " + cmd);
+// continue;
+// }
+ os.write((cmd + "\n").getBytes());
+ Log.d("ShellUtils", "Executing command: " + cmd);
+ }
+ os.write("exit\n".getBytes());
+ os.flush();
+ }
+
+ try {
+ // 执行命令、等待解决
+ process.waitFor();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // 恢复中断
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error executing commands", e);
+ }
+
+ // 等待子线程完成
+ stdThread.join();
+ errThread.join();
+
+ } catch (InterruptedIOException e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error reading stdout: Interrupted", e);
+ Thread.currentThread().interrupt(); // 恢复线程的中断状态
+ } catch (Exception e) {
+ LogUtils.d(Log.ERROR, "ShellUtils", "Error executing commands", e);
+ } finally {
+ if (process != null) {
+ process.destroy();
+ }
+ }
+ return results;
+ }
+
+ public static boolean hasRootAccess() {
+ // 记录是否出现安全异常
+ boolean hasSecurityError = false;
+
+ // 检查二进制文件
+ String[] binariesToCheck = {"su", "xu", "vu"};
+ for (String bin : binariesToCheck) {
+ try {
+ if (hasBin(bin)) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ hasSecurityError = true;
+ LogUtils.d(Log.ERROR, "ShellUtils", "Security exception while checking: " + bin, e);
+ }
+ }
+
+ // 判断如果发生安全异常则反馈问题
+ if (hasSecurityError) {
+ Log.w("ShellUtils", "Potential security error detected while checking root access.");
+ }
+
+ // 没有找到合法的二进制文件,则认为无root权限
+ return false;
+ }
+}
diff --git a/app/src/main/java/com/android/grape/util/ShellUtils.kt b/app/src/main/java/com/android/grape/util/ShellUtils.kt
index cb5fd09..3285246 100644
--- a/app/src/main/java/com/android/grape/util/ShellUtils.kt
+++ b/app/src/main/java/com/android/grape/util/ShellUtils.kt
@@ -558,7 +558,7 @@ object ShellUtils {
return result
}
- fun unzipAPkSh(zipFileName: String, dataDir: String) {
+ fun unzipScriptSh(zipFileName: String, dataDir: String) {
try {
val file = File(dataDir)
if (!file.exists()) {
@@ -571,6 +571,19 @@ object ShellUtils {
e.printStackTrace()
}
}
+ fun unzipAPkSh(zipFileName: String, dataDir: String) {
+ try {
+ val file = File(dataDir)
+ if (!file.exists()) {
+ FileUtils.forceCreteDir(file)
+ }
+ val cmd = "unzip -o " + FileUtils.CACHE_PATH + File(zipFileName).name + " -d " + dataDir
+ val unzipResult = MockTools.execRead(cmd)
+ Log.i("ShellUtils", "unZipFileSh-> cmd:$unzipResult")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
/**
* 执行shell命令以检索指定文件的内容。
diff --git a/app/src/main/java/com/android/grape/util/TaskUtils.kt b/app/src/main/java/com/android/grape/util/TaskUtils.kt
index e1d9668..326d661 100644
--- a/app/src/main/java/com/android/grape/util/TaskUtils.kt
+++ b/app/src/main/java/com/android/grape/util/TaskUtils.kt
@@ -135,7 +135,7 @@ object TaskUtils {
}
fun isInstallRet(): Boolean {
- return installRet ?: false
+ return installRet == true
}
fun setAfLog(afLogV: String) {