UnsatisfiedLinkError: dlopen failed: “/data/app/~~xxxxx==/lib/arm64/.so“ has bad ELF magic: 00000000

一、错误描述:
调试某Android硬件盒子,在升级app后,断电重启,出现以下错误信息:UnsatisfiedLinkError: dlopen failed: “/data/app/~~pGPujfYZls2be5Bj5rrwSg==/xxxx(这里是包名)-m5mN2cWGRTn-ZUO_CY4Fng==/lib/arm64/xxx_jni.so” has bad ELF magic: 00000000

二、错误解析:
这个错误表示在加载共享库时发生了问题。下面逐个解释每部分的含义:
1)UnsatisfiedLinkError:这是Java中的一个异常类型,表示无法满足对本地代码(如共享库)的链接请求。
2)dlopen failed:这指的是在尝试使用动态链接器打开共享库时发生了错误。
3)“/data/app/~~pGPujfYZls2be5Bj5rrwSg==/xxxxx-m5mN2cWGRTn-ZUO_CY4Fng==/lib/arm64/xxxx_jni.so”:这是共享库文件的完整路径。它指示共享库位于设备的特定路径中。
4)has bad ELF magic: 00000000:ELF(Executable and Linkable Format)是一种常见的二进制文件格式,用于可执行文件和共享库。这部分错误消息指示共享库的 ELF 魔数不正确,魔数应该是一个特定的值,但此处为 00000000,表示共享库的文件格式不正确。
综上所述,该错误表示应用程序在尝试加载共享库时遇到了问题。可能的原因是共享库文件损坏、找不到so文件、与设备架构不匹配或缺少依赖项。需要获取正确的共享库文件,确保与设备架构兼容,并检查是否存在所需的依赖项。

三、尝试解决:
该问题是在断电重启后发生的,可能有以下一些原因导致该错误:
文件系统损坏:断电重启可能导致文件系统损坏,特别是如果共享库文件在断电时正在被访问或修改。这可能会导致共享库文件出现损坏或不完整的情况。可以尝试对文件系统进行修复或重新安装应用程序来解决此问题。
数据丢失:断电重启可能导致应用程序数据的丢失,包括共享库文件。如果共享库文件被删除或丢失,加载时会出现错误。可以尝试重新安装应用程序来确保所有相关文件完整。
配置丢失:断电重启后,应用程序的配置文件或设置可能会丢失或损坏。如果共享库的路径或其他相关配置发生了变化,加载共享库时会发生错误。可以尝试重新配置应用程序或还原先前的配置来解决问题。

四、最终解决方案:
在app升级完成后,执行sync命令,调试阶段可通过:adb shell sync来同步。代码中可以用ShellUtils.execCommand(“sync”, false);来执行该命令。

五、关于sync命令
【adb shell sync 命令】
1)在shell中执行;
2)将内存缓冲区中的数据写入到磁盘;

【adb sync 命令】
命令意思:同步更新/data/或/system/下的数据

【命令用法】
1)adb sync [directory];如果不指定目录,将同步更新/data/和/system/
2)adb sync (将内存缓冲区的数据写入磁盘)

【adb -s ip:port shell sync 命令】
1)将内存缓冲区中的数据 写入到磁盘
2)如果不指定目录,将同步更新/data/和/system/

六、ShellUtils工具类


import androidx.annotation.NonNull;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

/**
 * description:ShellUtils,通过Java代码执行adb Shell命令,Shell命令支持执行String(单个命令), List(多个命令),String[](多个命令)
 * author: Trinea
 * date: 2022/10/24
 * update: 2022/10/24 -- 17:38
 * version:
 */
public class ShellUtils {
    public static final String COMMAND_SU = "su";
    public static final String COMMAND_SH = "sh";
    public static final String COMMAND_EXIT = "exit\n";
    public static final String COMMAND_LINE_END = "\n";


    private ShellUtils() {
        throw new AssertionError();
    }


    /**
     * check whether has root permission,检测是否有root权限
     *
     * @return true--有;false--没有
     */
    public static boolean checkRootPermission() {
        return execCommand("echo root", true, false).result == 0;
    }


    /**
     * execute shell command, default return result msg,执行shell命令,默认返回消息串
     *
     * @param command command
     * @param isRoot  whether need to run with root 是否以su用户执行(需要手机已经root)
     * @return CommandResult
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(String command, boolean isRoot) {
        return execCommand(new String[]{command}, isRoot, true);
    }


    /**
     * execute shell commands, default return result msg
     *
     * @param commands command list
     * @param isRoot   whether need to run with root 是否以su用户执行(需要手机已经root)
     * @return CommandResult
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(List<String> commands, boolean isRoot) {
        return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
    }


    /**
     * execute shell commands, default return result msg
     *
     * @param commands command array 依次要执行的shell命令数组
     * @param isRoot   whether need to run with root 是否以su用户执行(需要手机已经root)
     * @return CommandResult
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(String[] commands, boolean isRoot) {
        return execCommand(commands, isRoot, true);
    }


    /**
     * execute shell command
     *
     * @param command         command  要执行的shell命令
     * @param isRoot          whether need to run with root 是否以su用户执行(需要手机已经root)
     * @param isNeedResultMsg whether need result msg 是否存储命令执行成功及失败后的信息
     * @return CommandResult
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
        return execCommand(new String[]{command}, isRoot, isNeedResultMsg);
    }


    /**
     * execute shell commands
     *
     * @param commands        command list 依次要执行的shell命令集合
     * @param isRoot          whether need to run with root 是否以su用户执行(需要手机已经root)
     * @param isNeedResultMsg whether need result msg 是否存储命令执行成功及失败后的信息
     * @return CommandResult
     * @see ShellUtils#execCommand(String[], boolean, boolean)
     */
    public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {
        return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
    }


    /**
     * execute shell commands
     *
     * @param commands        command array  依次要执行的shell命令数组
     * @param isRoot          whether need to run with root 是否以su用户执行(需要手机已经root)
     * @param isNeedResultMsg whether need result msg 是否存储命令执行成功及失败后的信息
     * @return <ul>
     * <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and
     * {@link CommandResult#errorMsg} is null.</li>
     * <li>if {@link CommandResult#result} is -1, there maybe some exception.</li>
     * </ul>
     */
    public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }


        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;


        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }

                // do not use os.writeBytes(command), avoid chinese charset error
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();


            result = process.waitFor();
            // get command result
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s);
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            if (process != null) {
                process.destroy();
            }
        }
        return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
                : errorMsg.toString());
    }


    /**
     * result of command,命令执行后返回的数据结构
     * <ul>
     * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, same to execute in
     * linux shell</li>
     * <li>{@link CommandResult#successMsg} means success message of command result</li>
     * <li>{@link CommandResult#errorMsg} means error message of command result</li>
     * </ul>
     *
     * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16
     *
     * 应用场景实例:
     *
     *  (1) 拷贝文件
     * 原理是adb执行命令:
     * mount -o rw,remount /system
     * cp /mnt/sdcard/xx.apk /system/app/
     * Java代码如下:
     *
     * String[] commands = new String[] { "mount -o rw,remount /system", "cp /mnt/sdcard/xx.apk /system/app/" };
     * CommandResult result = ShellUtils.execCommand(commands, true);
     * 注意一般拷贝文件是不需要root的,上面用root是因为需要拷贝到/system/app/下面
     *
     * (2) 静默安装和卸载
     * Android root权限静默安装或卸载应用,原理是执行命令:pm install apkFilePath及pm uninstall packageName
     * 具体代码可见:PackageUtils installSilent(Context context, String filePath, String pmParams)
     *
     * (3)获取系统设置->存储->首选安装位置
     * 原理是执行命令:pm get-install-location
     * 具体代码可见:PackageUtils getInstallLocation()
     *
     * (4) Android修改hosts文件
     * 原理是执行命令:
     * mount -o rw,remount /system
     * echo “127.0.0.1 localhost” > /etc/hosts
     * echo “185.31.17.184 github.global.ssl.fastly.net” >> /etc/hosts
     * chmod 644 /etc/hosts
     * 代码如下:
     * Java
     *
     * List<String> commnandList = new ArrayList<String>();
     * commnandList.add("mount -o rw,remount /system");
     * commnandList.add("echo \"127.0.0.1 localhost\" > /etc/hosts");
     * commnandList.add("echo \"185.31.17.184 github.global.ssl.fastly.net\" >> /etc/hosts");
     * commnandList.add("chmod 644 /etc/hosts");
     * CommandResult result = ShellUtils.execCommand(commnandList, true);
     *
     * 用echo命令改hosts文件不用重启可以直接生效
     */
    public static class CommandResult {

        /**
         * result of command:result表示执行的结果,根据linux命令执行规则,0表示成功,其他为相应错误码
         **/
        public int result;
        /**
         * success message of command result:successMsg存储执行成功后的输出信息,errorMsg存储执行失败后的输出信息
         **/
        public String successMsg;
        /**
         * error message of command result:失败信息,如果isNeedResultMsg为false,successMsg和errorMsg会始终为空,而result依然为正常结果
         **/
        public String errorMsg;


        public CommandResult(int result) {
            this.result = result;
        }


        public CommandResult(int result, String successMsg, String errorMsg) {
            this.result = result;
            this.successMsg = successMsg;
            this.errorMsg = errorMsg;
        }

        @NonNull
        @Override
        public String toString() {
            return "CommandResult{" +
                    "result=" + result +
                    ", successMsg='" + successMsg + '\'' +
                    ", errorMsg='" + errorMsg + '\'' +
                    '}';
        }
    }
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值