From afd85cd10b71082b1d5e79468c8e7ff4adbc7a12 Mon Sep 17 00:00:00 2001 From: Administrator Date: Fri, 18 Jul 2025 18:26:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=AE=89=E8=A3=85=EF=BC=8C?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E5=B7=A5=E5=85=B7=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dbnavigator.xml | 149 ++++++- .../java/com/android/grape/MainActivity.kt | 1 + .../java/com/android/grape/data/Device.kt | 4 +- .../grape/sai/ShellSaiPackageInstaller.kt | 3 +- .../java/com/android/grape/util/AppUtils.kt | 2 +- .../com/android/grape/util/BackupUtils.kt | 4 +- .../com/android/grape/util/DeviceUtils.kt | 55 ++- .../java/com/android/grape/util/FileUtils.kt | 4 +- .../java/com/android/grape/util/MockTools.kt | 4 +- .../com/android/grape/util/ScriptUtils.kt | 3 +- .../com/android/grape/util/ShellUtil.java | 380 ++++++++++++++++++ .../java/com/android/grape/util/ShellUtils.kt | 15 +- .../java/com/android/grape/util/TaskUtils.kt | 2 +- 13 files changed, 607 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/android/grape/util/ShellUtil.java 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) {