解决百度地图在模拟器上运行报 java.lang.IllegalArgumentException: No config chosen问题

解决百度地图在模拟器上运行报 java.lang.IllegalArgumentException: No config chosen 问题

1. 问题复现

在近期公司使用模拟器(网易MuMu)进行项目演示时,在进入存在百度地图(Android版本 7.4.2版本)之后,页面出现奔溃,后台日志为:

Back traces starts.
java.lang.IllegalArgumentException: No config chosen
com.baidu.platform.comapi.map.h$a.chooseConfig(GLTextureView.java:655)
com.baidu.platform.comapi.map.h$e.a(GLTextureView.java:789)
com.baidu.platform.comapi.map.h$f.l(GLTextureView.java:1164)
com.baidu.platform.comapi.map.h$f.run(GLTextureView.java:1002)

2. 查找源码,定位问题

经过问题的复盘,找到了是位于源码位置报错的:

com.baidu.platform.comapi.map.h$a.chooseConfig(GLTextureView.java:655)

具体代码位置如下:

com.baidu.platform.comapi.map.h

类下面的一个抽象类 a ,实现了EGLConfigChooser 接口,在实现chooseConfig接口时报错:

private abstract class a implements EGLConfigChooser {
        protected int[] a;

        public a(int[] configSpec) {
            this.a = this.a(configSpec);
        }

        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {            
         		 // 代码省略... 
             EGLConfig config = this.a(egl, display, configs);
             if (config == null) {
                throw new IllegalArgumentException("No config chosen");
             } else {
                return config;
             }
        }
  	
      abstract EGLConfig a(EGL10 var1, EGLDisplay var2, EGLConfig[] var3);

}

我们可以看到 EGLConfig这个类是由a方法返回的,我们可以看到,当config==null 时,会直接报出异常IllegalArgumentException,那么我们可以查看一下这个抽象类a是由谁来集成的?

通过搜索源码,它的继承方式是这样的:

package com.baidu.platform.comapi.map;

public class h extends TextureView {
  
  private abstract class a implements EGLConfigChooser {
    
  }
  
  private class b extends com.baidu.platform.comapi.map.h.a {
        private int[] j = new int[1];
        protected int c;
        protected int d;
        protected int e;
        protected int f;
        protected int g;
        protected int h;

        public b(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) {
            super(new int[]{12324, redSize, 12323, greenSize, 12322, blueSize, 12321, alphaSize, 12325, depthSize, 12326, stencilSize, 12344});
            this.c = redSize;
            this.d = greenSize;
            this.e = blueSize;
            this.f = alphaSize;
            this.g = depthSize;
            this.h = stencilSize;
        }

        public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
            EGLConfig[] var4 = configs;
            int var5 = configs.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                EGLConfig config = var4[var6];
                int d = this.a(egl, display, config, 12325, 0);
                int s = this.a(egl, display, config, 12326, 0);
                if (d >= this.g && s >= this.h) {
                    int r = this.a(egl, display, config, 12324, 0);
                    int g = this.a(egl, display, config, 12323, 0);
                    int b = this.a(egl, display, config, 12322, 0);
                    int a = this.a(egl, display, config, 12321, 0);
                    if (r == this.c && g == this.d && b == this.e && a == this.f) {
                        return config;
                    }
                }
            }

            return null;
        }

        private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {
            return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : defaultValue;
        }
  }
  
  private class i extends com.baidu.platform.comapi.map.h.b {
        public i(boolean withDepthBuffer) {
            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
        }
    }
  
}

综上所属,h下面的a,bi的关系为:

我们可以看到 h.c中其实没有a方法实现的,那么a方法的实现就是在h.b中了,我们可以来简单看一下h.b方法的实现:

        public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
            EGLConfig[] var4 = configs;
            int var5 = configs.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                EGLConfig config = var4[var6];
                int d = this.a(egl, display, config, 12325, 0);
                int s = this.a(egl, display, config, 12326, 0);
                if (d >= this.g && s >= this.h) {
                    int r = this.a(egl, display, config, 12324, 0);
                    int g = this.a(egl, display, config, 12323, 0);
                    int b = this.a(egl, display, config, 12322, 0);
                    int a = this.a(egl, display, config, 12321, 0);
                    if (r == this.c && g == this.d && b == this.e && a == this.f) {
                        return config;
                    }
                }
            }

            return null;
        }

        private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {
            return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : defaultValue;
        }

这里我们可以看到,当执行r == this.c && g == this.d && b == this.e && a == this.f为真时,才能返回对应的config对象,如果都不匹配,那么将会导致返回null·,今儿导致程序奔溃。问题找到了,我们应该怎么去改它呢?

3. 通过源码去修复它

我也不拐弯抹角了,经过对源码的分析,列举一下自己对这个问题修复的看法。首先,我们知道了问题所在的地方,那么我们是否在方法类b中的a方法永远不返回null,那样就不会导致出现No config chosen异常,虽然这种方法会导致所选择的EGLConfig和所需要的config不匹配,导致页面存在拉伸或者压缩的问题,但是这相比于奔溃,应该会好很多。那么就按照这个说的干吧。

首先,要修改返回值,使用它原有的逻辑肯定是不行的,但是我们返现这个 h.a抽象类实现的是 EGLConfigChooser,它是来自android.opengl.GLSurfaceView下的一个接口,比较熟悉openGL的人应该比较熟悉它:

    public interface EGLConfigChooser {
        /**
         * Choose a configuration from the list. Implementors typically
         * implement this method by calling
         * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
         * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
         * @param egl the EGL10 for the current display.
         * @param display the current display.
         * @return the chosen configuration.
         */
        EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
    }

那我能不能自定义一下我们的h.ah.bh.i类呢,把源码拷一遍,然后把a方法返回值修改一下即可,好,那么说干就干:

h.a类如下:

public abstract class ParentEGLConfigChooser implements GLSurfaceView.EGLConfigChooser {

    protected int[] a;

    public ParentEGLConfigChooser(int[] configSpec) {
        this.a = this.a(configSpec);
    }

    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
        int[] num_config = new int[1];
        if (!egl.eglChooseConfig(display, this.a, (EGLConfig[])null, 0, num_config)) {
            throw new IllegalArgumentException("eglChooseConfig failed");
        } else {
            int numConfigs = num_config[0];
            if (numConfigs <= 0) {
                throw new IllegalArgumentException("No configs match configSpec");

            } else {
                EGLConfig[] configs = new EGLConfig[numConfigs];
                if (!egl.eglChooseConfig(display, this.a, configs, numConfigs, num_config)) {
                    throw new IllegalArgumentException("eglChooseConfig#2 failed");
                } else {
                    EGLConfig config = this.a(egl, display, configs);
                    if (config == null) {
                        throw new IllegalArgumentException("No config chosen");
                    } else {
                        return config;
                    }
                }
            }
        }
    }

    abstract EGLConfig a(EGL10 var1, EGLDisplay var2, EGLConfig[] var3);


    private int[] a(int[] configSpec) {
        int len = configSpec.length;
        int[] newConfigSpec = new int[len + 2];

        System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
        newConfigSpec[len - 1] = 12352;
        newConfigSpec[len] = 4;
        newConfigSpec[len + 1] = 12344;
        return newConfigSpec;

    }

}

对于h.b类,我们可以实现如下:

public class SubEGLConfigChooser extends ParentEGLConfigChooser {

    private final int[] j = new int[1];
    protected int c;
    protected int d;
    protected int e;
    protected int f;
    protected int g;
    protected int h;

    public SubEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize) {
        super(new int[]{12324, redSize, 12323, greenSize, 12322, blueSize, 12321, alphaSize, 12325, depthSize, 12326, stencilSize, 12344});
        this.c = redSize;
        this.d = greenSize;
        this.e = blueSize;
        this.f = alphaSize;
        this.g = depthSize;
        this.h = stencilSize;
    }

    public EGLConfig a(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {

        BaseLog.i("----show the a------>>" + egl + "---->>" + display + "---->>" + Arrays.toString(configs));

        for (EGLConfig config : configs) {
            int d = this.a(egl, display, config, 12325);
            int s = this.a(egl, display, config, 12326);
            if (d >= this.g && s >= this.h) {
                int r = this.a(egl, display, config, 12324);
                int g = this.a(egl, display, config, 12323);
                int b = this.a(egl, display, config, 12322);
                int a = this.a(egl, display, config, 12321);
                if (r == this.c && g == this.d && b == this.e && a == this.f) {
                    return config;
                }
            }
        }

        //TODO 直接修改这里,返回第一个 configs[0], 暂时还未发现任何异常
        return configs[0];
    }

    private int a(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute) {
        return egl.eglGetConfigAttrib(display, config, attribute, this.j) ? this.j[0] : 0;
    }
}

同样,对于h.i类,我们可以自定义类为:

public class TargetEGLConfigChooser extends SubEGLConfigChooser{
    
    public TargetEGLConfigChooser() {
        super(8, 8, 8, 0, 16 , 0);
    }
}

这三个类我们已经写好了,那么如何将我们的TargetEGLConfigChooser 替换成目标h.i方法呢?这个可能要花一些时间,我们来大致了解一下 BaiduMap的基础架构,我们以 TextureMapView为例子:

TextureMapView是继承自ViewGroup, 它有一个私有属性值b,其类型为MapTextureView, 属性bTextureMapView的初始化方法中被初始化:

MapTextureView中,首先它是继承自com.baidu.platform.comapi.map.h的:

同时,我们在h类中找到了h,h是一个EGLConfigChooser类型的接口,

在这里插入图片描述

通过程序分析, 那么这个h的实现类就是咋们的h.i. 主要问题分析完成了,那么就好做了,直接使用反射,将我们的h的实现类直接由h.i替换成我们的 TargetEGLConfigChooser即可,代码很简单,就几行:

public class TextureMapViewFix {

    public static void tryToFixException(TextureMapView mapView) {

        try {
            Field b = mapView.getClass().getDeclaredField("b");  // 找到b
            b.setAccessible(true);

            Object bObject = b.get(mapView);
            BaseLog.i("bObject = " + bObject);

            if (null == bObject) {
                BaseLog.i("bObject is null and return");
                return;
            }

            Field h = bObject.getClass().getSuperclass().getDeclaredField("h"); //找到其父类,然后查找子元素h
            h.setAccessible(true);

            Object aObject = h.get(bObject);
            BaseLog.i("aObject = " + aObject);

            h.set(bObject, new TargetEGLConfigChooser());  //替换成咋们自定义的目标类  TargetEGLConfigChooser
            
            Object aObject1 = h.get(bObject);
            BaseLog.i("aObject1 = " + aObject1);  //检查是否更新成功
            
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4. 总结

可能baidu地图的源码是混淆的,所以啃起来不是特别的顺利,还是耐着性子看完了,问题其实并不复杂,弄清楚逻辑就比较简单了,可能就是java的反射需要点功底,其它的都好说。如果有任何问题,可以add v:javainstalling,备注:baidu.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/333832.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

域环境权限提升

Windows系统配置错误 在Windows系统中&#xff0c;攻击者通常会通过系统内核溢出漏来提权&#xff0c;但是如果碰到无法通过系统内核溢出漏洞法国提取所在服务器权限的情况&#xff0c;就会系统中的配置错误来提权。Windows系统中常见哦欸之错误包括管理员凭证配置错误&#x…

Linux7 安装 Oracle 19C RAC 详细图文教程

实战篇&#xff1a;Linux7 安装 Oracle 19C RAC 详细图文教程 本文是按照&#xff1a;https://www.modb.pro/db/154424的思路进行编写 一、安装前规划 安装RAC前&#xff0c;当然要先做好规划。具体包含以下几方面&#xff1a; 节点主机版本主机名实例名Grid/Oracle版本Publi…

【论文简介】个性化真实人像生成方法(2024.01.15发布,即将开源)

零样本身份保留生成方法&#xff1a;声称效果好于PhotoMaker&#xff08;即将开源&#xff09; 2401.InstantID: Zero-shot Identity-Preserving Generation in Seconds &#xff1a; 项目主页&#xff1a;https://instantid.github.io/ 一、简介 本文的主要内容是介绍了一种…

【MATLAB】SVMD_LSTM神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 SVMD-LSTM神经网络时序预测算法是一种结合了单变量经验模态分解&#xff08;Singular Value Decomposition&#xff0c;SVD&#xff09;和长短期记忆神经网络&#xff08;LSTM&#xff09…

十年很短,编程很难

前天冲浪看到的一篇文章&#xff0c;深有感触&#xff0c;翻译给大家一起看看吧 许多年前&#xff0c;当我仍是一名主修计算机科学的高年级学生时&#xff0c;我整天浏览各种在线招聘信息&#xff0c;希望能找到适合程序员的实习职位 除了实习职位&#xff0c;我偶尔也会点击一…

统计学R语言实验8 :线性回归

统计学R语言实验8 &#xff1a;线性回归 一、实验目的 1. 掌握理解线性回归的相关概念。 2. 掌握理解线性回归的相关方法。 3. 熟悉R语言等语言的集成开发环境。 二、实验分析与内容 完成教材P132的第2题 散点图 将 shouru 向量作为 x 轴&#xff0c;zhichu 向量作为 y 轴…

各模块的实现

注册模块&#xff1a; 注册使用手机号发送验证码注册的方式&#xff0c;使用的是阿里云的短信发送服务&#xff0c;然后进行认证&#xff0c;有个60s的时间&#xff0c;可以存到redis中&#xff0c;key是手机号&#xff0c;value是验证码。 使用Spring自带的BCryptPasswordEn…

《亚太教育》期刊投稿方式

《亚太教育》杂志是国家新闻出版总署批准的正规教育类期刊&#xff0c;旨在传播教育文化信息和动态&#xff0c;展示教育实践模式和经验&#xff0c;搭建教育科研成果交流平台。杂志将致力于服务教育事业的创新发展&#xff0c;传播教育文化新信息&#xff0c;展示教育实践新模…

java基础:求数组的最值

方法一&#xff1a;顺序查找 先假设数组第一个元素为最值&#xff0c;然后和数组里的数按顺序进行比较得出最值&#xff0c;所以叫顺序查找。 代码如下 package idea;public class arr_int {public static void main(String[] args) { // 初始化一个数组int[] arr {12…

第十一章 请求响应

第十一章 请求响应 1.概述2.请求-postman工具3.请求-简单参数&实体参数4.请求-数组集合参数5.请求-日期参数&JSON参数6.请求-路径参数7.响应-ResponseBody&统一响应结果8.响应-案例 1.概述 将前端发送的请求封装为HttpServletRequest对象 在通过HttpServletRespo…

经典数据库练习题及答案

数据表介绍 --1.学生表 Student(SId,Sname,Sage,Ssex) --SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表 Course(CId,Cname,TId) --CId 课程编号,Cname 课程名称,TId 教师编号 --3.教师表 Teacher(TId,Tname) --TId 教师编号,Tname 教师姓名 --4.成绩…

freeswitch on centos dockerfile模式

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 centos7 docker上编译安装fs的流程记录&#xff0c;本文使用dockerfile模式。 环境 docker engine&#xff1a;Version 24.0.6 centos docker&#xff1a;7 freeswitch&#xff1a;v1.6.20 dockerfile 创建空目录…

基于springboot+vue的校园周边美食探索及分享平台系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

使用 MinIO 和 PostgreSQL 简化数据事件

本教程将教您如何使用 Docker 和 Docker Compose 在 MinIO 和 PostgreSQL 之间设置和管理数据事件&#xff0c;也称为存储桶或对象事件。 您可能已经在利用 MinIO 事件与外部服务进行通信&#xff0c;现在您将通过使用 PostgreSQL 自动化和简化数据事件管理来增强数据处理能力…

怎么处理vue项目中的错误详解

文章目录 一、错误类型二、如何处理后端接口错误代码逻辑问题全局设置错误处理生命周期钩子 三、源码分析小结参考文献 一、错误类型 任何一个框架&#xff0c;对于错误的处理都是一种必备的能力 在 Vue 中&#xff0c;则是定义了一套对应的错误处理规则给到使用者&#xff0…

一万六千字大章:Chrome 浏览器插件 V3 版本 Manifest.json 文件全字段解析

Chrome 浏览器插件 V3 版本 Manifest.json 文件全字段解析 Manifest.json 文件格式 每个扩展程序的根目录中都必须有一个 manifest.json 文件&#xff0c;其中列出了有关该扩展程序的结构和行为的重要信息。 1、Demo 展示 1. 最小文件 {"manifest_version": 3,&quo…

Git入门详细教程

一、Git概述&#x1f387; Git官网 Git是一个开源的分布式版本控制系统&#xff0c;用于跟踪文件的变化和协作开发。它允许多个开发者在同一项目中共同工作&#xff0c;并能够有效地管理代码的版本和历史记录。Git可以帮助开发团队更好地协作&#xff0c;追踪代码变更&#xf…

云轴科技ZStack 助力广西某地级市建设市级警务云视频系统

某市属于广西壮族自治区辖地级市&#xff0c;省域副中心城市&#xff0c;选择云轴科技ZStack 超融合解决方案支撑警务云视频监控联网管理系统&#xff08;警务云视频系统&#xff09;&#xff0c;实现了该市对各辖区视频资源统一管理&#xff1b;同时也满足了该市警务云视频系统…

技术分享 | App常见bug解析

在 app 产品测试过程中&#xff0c;可能会遇到很多不同类型的 Bug。知道了可能 Bug 的类型&#xff0c;有利于在测试过程中更好的预防这些问题的发生。 功能Bug 内容显示错误 前端页面展示的内容有误。 这种错误的产生有两种可能 前端代码写的文案错误接口返回值错误 功能…

windows安装mysql5.7

看了如何学习mysql后&#xff0c;就开始本地安装mysql&#xff0c;开始学习了。 1.官网下载 官网地址&#xff1a; https://dev.mysql.com/downloads/mysql/ 选择5.7版本 点击 “No thanks, just start my download”开始下载 下载64位的压缩包版 解压下载好的.zip文件&#xf…