• 处理华为Framework层中curosr和空指针问题(反编译ROM和Hook动态代理)


    最近一直忙着解决公司游戏的Bug,但有些问题是顽固分子,许多个迭代都没解决掉,但不处理总觉有一根刺,在扎着肉。

    本篇是记录如何处理手机系统ROM中Framework中报错,可以适用不同的手机厂商。

    bugly上的问题:

    android.database.CursorWindowAllocationException
    Cursor window could not be created from binder.
    android.database.CursorWindow.(CursorWindow.java:137)
    android.database.CursorWindow.(CursorWindow.java)
    android.database.CursorWindow$1.createFromParcel(CursorWindow.java:685)
    android.database.CursorWindow$1.createFromParcel(CursorWindow.java:684)
    android.database.BulkCursorDescriptor.readFromParcel(BulkCursorDescriptor.java:75)
    android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:34)
    android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:32)
    android.content.ContentProviderProxy.query(ContentProviderNative.java:424)
    android.content.ContentResolver.query(ContentResolver.java:541)
    android.content.ContentResolver.query(ContentResolver.java:476)
    com.huawei.android.hwaps.OperateExperienceLib.isGameInfoExist(OperateExperienceLib.java:497)
    com.huawei.android.hwaps.OperateExperienceLib.saveAPSResult(OperateExperienceLib.java:429)
    com.huawei.android.hwaps.EventAnalyzed.setAdaptFPS(EventAnalyzed.java:1373)
    com.huawei.android.hwaps.EventAnalyzed.processAnalyze(EventAnalyzed.java:1726)
    android.view.HwNsdImpl.adaptPowerSave(HwNsdImpl.java:1182)
    android.view.ViewRootImpl$EarlyPostImeInputStage.processPointerEvent(ViewRootImpl.java:4648)
    android.view.ViewRootImpl$EarlyPostImeInputStage.onProcess(ViewRootImpl.java:4617)
    android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4258)
    android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6690)
    android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6664)
    android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6625)
    android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6819)
    android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:192)
    android.os.MessageQueue.nativePollOnce(Native Method)
    android.os.MessageQueue.next(MessageQueue.java:356)
    android.os.Looper.loop(Looper.java:138)
    android.app.ActivityThread.main(ActivityThread.java:6623)
    java.lang.reflect.Method.invoke(Native Method)
    com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    从代码报错点来看是,cursor 过多未关闭,存在泄漏,产生的原因可能是cursor未关闭或者fd 过多或者是内存不足。

    因报错点发生在华为ROM的framework层,因此要先考虑获取到对应的framework.dex, 查看代码调用流程,再来确定解决方案。

    设备信息:

    设备机型系统版本ROM
    WAS-AL00Android 8.0.0,level 26HuaWei/EMOTION

    1.前期准备:反编译华为Rom系统

    可考虑下载华为固件Rom 或者通过adb pull 获取该机型的framework.dex, 详细操作,请阅读Android反编译之各大手机厂商的系统(adb pull和Rom包)

    经过一些列操作,获取到framework有关的dex,如下图所示:
    在这里插入图片描述

    2.源码分析定位

    通过gui 工具打开华为rom 的framework 层源码。
    在这里插入图片描述

    先从ViewRootImpl#EarlyPostImeInputStage的onProcess()开始入手,追查起。

    android/view/ViewRootImpl:

        final class EarlyPostImeInputStage extends InputStage {
    
            protected int onProcess(QueuedInputEvent q) {
                if (q.mEvent instanceof KeyEvent) {
                    return processKeyEvent(q);
                }
                if ((q.mEvent.getSource() & 2) != 0) {
                    return processPointerEvent(q);
                }
                return 0;
            }
    
            private int processPointerEvent(QueuedInputEvent q) {
                MotionEvent event = q.mEvent;
                if (ViewRootImpl.this.mTranslator != null) {
                    ViewRootImpl.this.mTranslator.translateEventInScreenToAppWindow(event);
                }
    			    //若是rom 支持aps功能和包名和进程名匹配的情况下
                if (HwFrameworkFactory.getHwNsdImpl().isSupportAps() && HwFrameworkFactory.getHwNsdImpl().isGameProcess(ViewRootImpl.this.mContext.getPackageName())) {
                    HwFrameworkFactory.getHwNsdImpl().initAPS(ViewRootImpl.this.mView.getContext(), ViewRootImpl.this.mView.getResources().getDisplayMetrics().widthPixels, Process.myPid());
                    HwFrameworkFactory.getHwNsdImpl().adaptPowerSave(event);
                }
                int action = event.getAction();
                if (HwFrameworkFactory.getHwViewRootImpl().filterDecorPointerEvent(ViewRootImpl.this.mContext, event, action, ViewRootImpl.this.mWindowAttributes, ViewRootImpl.this.mDisplay)) {
                    return 1;
                }
    			//... 
                return 0;
            }
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    先来看下getHwNsdImpl()获取的对象,才能更好的了解源码调用过程。

    android/common/HwFrameworkFactory中:

      public static IHwNsdImpl getHwNsdImpl() {
            Factory obj = getImplObject();
            if (obj != null) {
                return obj.getHwNsdImpl();
            }
            return null;
      }
      private static Factory getImplObject() {
            if (obj != null) {
                return obj;
            }
            synchronized (mLock) {
                try {// 反射获取真正的HwFrameworkFactory实现类
                    obj = (Factory) Class.forName("huawei.android.common.HwFrameworkFactoryImpl").newInstance();
                } catch (Exception e) {
                    Log.e(TAG, ": reflection exception is " + e);
                }
            }
            //...
            return null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    HwFrameworkFactory 是一个封装的api 类,用于静态方法/工厂类方式,间接调用各种api。

    接下来,继续看下huawei/android/common/HwFrameworkFactoryImpl类中的getHwNsdImpl()

        public HwNsdImpl getHwNsdImpl() {
            return HwNsdImpl.getDefault();
        }
    
    • 1
    • 2
    • 3

    接下来看下android/view/HwNsdImpl

       public static HwNsdImpl getDefault() {
            if (mInstance == null) {
                mInstance = new HwNsdImpl();
            }
            return mInstance;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    经过一些列的追踪,可以了解到ViewRootImpl对象中调用的是HwNsdImpl中的方法。

    接下来看下,isGameProcess()isSupportAps()adaptPowerSave()等几个方法。

    2.1 华为framework 统计游戏fps 的条件
        public boolean isSupportAps() { 
            return SystemProperties.getInt("sys.aps.support", 0) > 0;
        }
    
    • 1
    • 2
    • 3

    从上面代码可知,isSupportAps()是检测系统rom 是否支持aps功能。

    接下来看下isGameProcess()

     private static IEventAnalyzed mEventAnalyzed = null;
    
        public boolean isGameProcess(String pkgName) {
            createEventAnalyzed();
            if (mEventAnalyzed != null) {
                return mEventAnalyzed.isGameProcess(pkgName);
            }
            return false;
        }
        public synchronized void createEventAnalyzed() {
            if (mEventAnalyzed == null) {
                mEventAnalyzed = HwapsWrapper.getEventAnalyzed();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来看下, com/huawei/android/hwaps/HwapsWrapper类中getEventAnalyzed():

        public static IEventAnalyzed getEventAnalyzed() {
            IHwapsFactory factory = getHwapsFactoryImpl();
            return factory != null ? factory.getEventAnalyzed() : null;
        }
    
        private static synchronized IHwapsFactory getHwapsFactoryImpl() {
            IHwapsFactory iHwapsFactory;
            synchronized (HwapsWrapper.class) {
                if (mFactory != null) {
                    iHwapsFactory = mFactory;
                } else {
                    try {
                        mFactory = (IHwapsFactory) Class.forName("com.huawei.android.hwaps.HwapsFactoryImpl").newInstance();
                    } catch (ClassNotFoundException e) {
                        Log.e(TAG, "reflection exception is " + e);
                    } catch (InstantiationException e2) {
                        Log.e(TAG, "reflection exception is " + e2);
                    } catch (IllegalAccessException e3) {
                        Log.e(TAG, "reflection exception is " + e3);
                    }
                    if (mFactory == null) {
                        Log.e(TAG, "failes to get HwapsFactoryImpl");
                    }
                    iHwapsFactory = mFactory;
                }
            }
            return iHwapsFactory;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    从上面代码可知, HwapsWrapper是一个封装api的类, 其真正调用是HwapsFactoryImpl类。

    com/huawei/android/hwaps/HwapsFactoryImpl

    public class HwapsFactoryImpl implements IHwapsFactory {
    
        //...
        public IEventAnalyzed getEventAnalyzed() {
            return new EventAnalyzed();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    经过一些列的波折,最终调用链是ViewRootImpl->IHwNsdImpl->EventAnalyzed类的方法:

    com/huawei/android/hwaps/EventAnalyzed

        //检查下是否是原始进程对应的包名
        private boolean isIdentifyProcess(String strPkgName) {
            if (!this.mHasIdentifyProcess) {
                if (SystemProperties.get("debug.aps.process.name", "").equals(strPkgName)) {
                    this.mIsGameProcess = true;
                } else {
                    this.mIsGameProcess = false;
                }
                this.mHasIdentifyProcess = true;
            }
            return this.mIsGameProcess;
        }
    
        public boolean isGameProcess(String pkgName) {
            if (this.mHasIdentifyProcess && !this.mIsGameProcess) {
                return this.mIsGameProcess;
            }
            if (isAPSReady()) {
                return isIdentifyProcess(pkgName); // 通常下,app主进程 是返回true
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    从上面可见,若pkgName是app 主进程名,是返回true的。

    这里注意点, EventAnalyzed 是com/huawei/android/hwaps/IEventAnalyzed接口的实现类,后面会用到。

    public interface IEventAnalyzed {
    
        //......
        boolean isGameProcess(String str);
        void processAnalyze(int i, long j, int i2, int i3, int i4, long j2);
        void setHasOnPaused(boolean z);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.2 华为 framework层是如何存储游戏的fps功能

    HwNsdImpl#adaptPowerSave()是调用EventAnalyzed#processAnalyze(),因此,接下来看下processAnalyze()

        public void processAnalyze(int aciton, long eventTime, int x, int y, int pointCount, long downTime) {
           //...
    	   else if (CUST_APP_TYPE != mGameType) {
                //...
                setAdaptFPS(gametype, openGLType, this.mLevel);
            }
        }
    	
    	public void setAdaptFPS(int gameType, int openGLType, int level) {
                //...
                else if (!this.mHasSetFPS) {
                    mGameType = gameType;
                    int recommendFPS = computeRecommendFPS(gameType, openGLType, level);
                    if (gameType == 8 || gameType == 9) {
                        this.mOperateExLib.saveAPSResult(gameType, recommendFPS, recommendFPS);
                    } else {
                        this.mOperateExLib.saveAPSResult(gameType, recommendFPS, mMinFps);
                    }
    				//.....
                }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    接下来看下com/huawei/android/hwaps/OperateExperienceLibsaveAPSResult():

        public void saveAPSResult(int gameType, int maxFPS, int minFPS) {
            this.mGameType = gameType;
            this.mMaxFPS = maxFPS;
            this.mMinFPS = minFPS;
            if (this.mIsExistInDataBase) {
                updateAppInfo();
            } else {
                insertAppInfo();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里发生了一点小变故,可能是同样的手机,同个大编号的系统rom 存在多个小版本,并没有找到isGameInfoExist()方法。

    但并不影响,咱们继续分析。看到最后,发现最终是华为系统收集app game 的周期性的fps 信息, 通过广播形式跨进程通信到其他系统app中。

    在通信前,会通过cursor查询下该游戏app是否存在,也就是bulgy上的报错点。解决方案,也是基于减少cursor的查询

    3.解决方案 Hook 代理

    3.1 思路分析

    1.通过hook 方式,代理调用EventAnalyzed类调用processAnalyze();
    2.经过上面的源码分析,可知HwNsdImpl类中mEventAnalyzed属性时hook 点;
    3.因IEventAnalyzed是一个抽象接口,考虑动态代理拦截其中的方法调用。

    3.2 编写相应的代码
      public static void hookHwFrameworkFactory() {
            if (isSafeHookHuawei()) {
                try {
                    Class<?> hwNsdImplClass = Class.forName("android.view.HwNsdImpl");
                    Method getDefaultMethod = hwNsdImplClass.getDeclaredMethod("getDefault");
                    getDefaultMethod.setAccessible(true);
                    // 获取HwNsdImpl 类对象
                    Object hwNsdImplObject = getDefaultMethod.invoke(null);
                    // 调用createEventAnalyzed(),先构建出真正的EventAnalyzed对象
                    Method createEventAnalyzedMethod = hwNsdImplClass.getDeclaredMethod("createEventAnalyzed");
                    createEventAnalyzedMethod.setAccessible(true);
                    createEventAnalyzedMethod.invoke(hwNsdImplObject);
                    // 获取真正的EventAnalyzed对象
                    Field mEventAnalyzedFiled = hwNsdImplClass.getDeclaredField("mEventAnalyzed");
                    mEventAnalyzedFiled.setAccessible(true);
                    Object oldFactory = mEventAnalyzedFiled.get(null);
                    // 构建IEventAnalyzed的代理对类
                    Class<?> iEventAnalyzedClass = Class.forName("com.huawei.android.hwaps.IEventAnalyzed");
                    Object proxyFactory = CommonProxy.startHook(oldFactory, iEventAnalyzedClass, new ProxyCallBack() {
                        @Override
                        public Object interrupt(CommonProxy proxy, Method method, Object[] args) throws Throwable {
                            Object result = null;
                            if (method.getName().equals("processAnalyze")) {
                                //处理bugly上的问题:https://bugly.qq.com/v2/crash-reporting/crashes/1105308248/33050435/report?pid=1&crashDataType=undefined
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
                                    //6.0到8.1的版本上屏蔽该方法的调用
                                } else {
                                    result = proxy.doRealInvoke(method, args);
                                }
                            } else {
                                result = proxy.doRealInvoke(method, args);
                            }
                            return result;
                        }
                    });
                    mEventAnalyzedFiled.set(null, proxyFactory);
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    3.3 云真机验证

    在云真机进行验证发现,mEventAnalyzed是非静态,通过静态方式获取直接报错,可能每个Rom中代码又有新的变化:

    08-29 19:39:29.633 W/System.err( 5126): java.lang.NullPointerException: null receiver
    08-29 19:39:29.635 W/System.err( 5126): 	at java.lang.reflect.Field.get(Native Method)
    08-29 19:39:29.635 W/System.err( 5126): 	at com.minitech.miniworld.HuaWeiHook.hookHwFrameworkFactory(HuaWeiHook.java:91)
    08-29 19:39:29.635 W/System.err( 5126): 	at org.appplay.lib.GameBaseActivity$7.run(GameBaseActivity.java:625)
    08-29 19:39:29.635 W/System.err( 5126): 	at android.os.Handler.handleCallback(Handler.java:761)
    08-29 19:39:29.635 W/System.err( 5126): 	at android.os.Handler.dispatchMessage(Handler.java:98)
    08-29 19:39:29.635 W/System.err( 5126): 	at android.os.Looper.loop(Looper.java:156)
    08-29 19:39:29.635 W/System.err( 5126): 	at android.app.ActivityThread.main(ActivityThread.java:6623)
    08-29 19:39:29.635 W/System.err( 5126): 	at java.lang.reflect.Method.invoke(Native Method)
    08-29 19:39:29.635 W/System.err( 5126): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
    08-29 19:39:29.635 W/System.err( 5126): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结合报错的机型,如下:

    在这里插入图片描述

    3.4 完善代码

    因此调整代码如下:

    public class HuaWeiHook {
        private static final String TAG = "HuaWeiHook";
    
        /**
         * 是否是华为rom
         *
         * @return
         */
        public static boolean isHuWeiRoom() {
            final String huawei_room_name = "huawei";
            boolean result=false;
            try {
                String brand = Build.BRAND;
                Log.i(TAG," room brand "+brand);
                if (!TextUtils.isEmpty(brand)) {
                    brand = brand.toLowerCase();
                }
                result=brand.contains(huawei_room_name);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!result){
                try {
                    String manufacturer = Build.MANUFACTURER;
                    Log.i(TAG," room  manufacturer "+ manufacturer);
                    if (!TextUtils.isEmpty(manufacturer)) {
                        manufacturer = manufacturer.toLowerCase();
                    }
                   result= manufacturer.contains(huawei_room_name);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    
        /**
         * 是否支持反射framework 层的api,9.0以下
         *
         * @return
         */
        public static boolean isSupportHook() {
            return Build.VERSION.SDK_INT < Build.VERSION_CODES.P;
        }
    
        /**
         * 检查是否满足华为机型反射调用
         *
         * @return
         */
        public static boolean isSafeHookHuawei() {
            return isHuWeiRoom() && isSupportHook();
        }
    
        private static AtomicBoolean init = new AtomicBoolean(false);
    
        public static void hookHwFrameworkFactory() {
            if (init.compareAndSet(false, true)) {
                boolean isSafe = isSafeHookHuawei();
                Log.i(TAG, " room huawei " + isSafe);
                if (isSafe) {// 非华为手机系统,不做处理
                    try {
                        Class<?> hwNsdImplClass = Class.forName("android.view.HwNsdImpl");
                        Method getDefaultMethod = hwNsdImplClass.getDeclaredMethod("getDefault");
                        getDefaultMethod.setAccessible(true);
                        // 获取HwNsdImpl 类对象
                        Object hwNsdImplObject = getDefaultMethod.invoke(null);
                        // 调用createEventAnalyzed(),先构建出真正的EventAnalyzed对象
                        Method createEventAnalyzedMethod = hwNsdImplClass.getDeclaredMethod("createEventAnalyzed");
                        createEventAnalyzedMethod.setAccessible(true);
                        createEventAnalyzedMethod.invoke(hwNsdImplObject);
                        // 获取真正的EventAnalyzed对象
                        Field mEventAnalyzedFiled = hwNsdImplClass.getDeclaredField("mEventAnalyzed");
                        mEventAnalyzedFiled.setAccessible(true);
                        //检查是否为静态属性
                        boolean static_access=false;
                        Object oldFactory =null;
                        try {
                            oldFactory=mEventAnalyzedFiled.get(null);
                            static_access=true;
                        }catch (Exception e){
                        }
                        if (oldFactory==null){
                            static_access=false;
                            oldFactory= mEventAnalyzedFiled.get(hwNsdImplObject);
                        }
                        // 构建IEventAnalyzed的代理对类
                        Class<?> iEventAnalyzedClass = Class.forName("com.huawei.android.hwaps.IEventAnalyzed");
                        Object proxyFactory = CommonProxy.startHook(oldFactory, iEventAnalyzedClass, new ProxyCallBack() {
                            @Override
                            public Object interrupt(CommonProxy proxy, Method method, Object[] args) throws Throwable {
                                Object result = null;
                                if (method.getName().equals("processAnalyze")) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
                                        //6.0到8.1的版本上屏蔽该方法的调用
                                        Log.i(TAG, " interrupt huawei processAnalyze method ");
                                    } else {
                                        result = proxy.doRealInvoke(method, args);
                                    }
                                } 
                                //...
    							else {
                                    result = proxy.doRealInvoke(method, args);
                                }
                                return result;
                            }
                        });
                        if (!static_access){
                            mEventAnalyzedFiled.set(hwNsdImplObject, proxyFactory);
                        }else {
                            mEventAnalyzedFiled.set(null,proxyFactory);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        /**
         * 构建一个通用的代理类
         */
        public static class CommonProxy implements InvocationHandler {
            protected Object oldObject;
            protected ProxyCallBack callBack;
    
            private CommonProxy(Object oldFactory, ProxyCallBack callBack) {
                this.oldObject = oldFactory;
                this.callBack = callBack;
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return callBack != null ? callBack.interrupt(this, method, args) : doRealInvoke(method, args);
            }
    
            /**
             * 调用原本的逻辑,继续走下去
             *
             * @param method
             * @param args
             * @return
             * @throws Throwable
             */
            public Object doRealInvoke(Method method, Object[] args) throws Throwable {
                return method.invoke(oldObject, args);
            }
    
            public static Object startHook(Object oldFactory, Class<?> interfaceClass, ProxyCallBack callBack) throws Exception {
                return Proxy.newProxyInstance(HuaWeiHook.class.getClassLoader(), new Class[]{interfaceClass}, new CommonProxy(oldFactory, callBack));
            }
        }
    
        public static interface ProxyCallBack {
            Object interrupt(CommonProxy proxy, Method method, Object[] args) throws Throwable;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157

    4.处理华为Framework中的其他问题(空指针)

    另外一个问题:

    java.lang.NullPointerException
    Attempt to invoke interface method 'java.util.Iterator java.util.List.iterator()' on a null object reference
    com.huawei.android.hwaps.EventAnalyzed.isBackground(EventAnalyzed.java:1932)
    com.huawei.android.hwaps.EventAnalyzed$1.run(EventAnalyzed.java:1956)
    android.os.Handler.handleCallback(Handler.java:743)
    android.os.Handler.dispatchMessage(Handler.java:95)
    android.os.Looper.loop(Looper.java:150)
    android.app.ActivityThread.main(ActivityThread.java:5621)
    java.lang.reflect.Method.invoke(Native Method)
    com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    通过一些列的反向逆推,找到调用链接。调用链接:EventAnalyzed#setHasOnPaused()->EventAnalyzed#checkBackground()->EventAnalyzed#isBackground()

    先来看下, com/huawei/android/hwaps/EventAnalyzed#setHasOnPaused()

     public void setHasOnPaused(boolean hasOnPaused) {
            boolean haspause = mHasOnPaused;
            mHasOnPaused = hasOnPaused;
            checkBackground();
            if (mApsThermal != null) {
                mApsThermal.stop();
            } else {
                ApsCommon.logI(TAG, "setHasOnPaused-ApsThermal is null");
            }
            if (mApsUserFeedback != null) {
                mApsUserFeedback.stop();
            } else {
                ApsCommon.logI(TAG, "setHasOnPaused-ApsUserFeedback is null");
            }
            //...  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    接下来看下checkBackground()

        private void checkBackground() {
            new Handler().postDelayed(new Runnable() {// 通过handler 延迟执行
                public void run() {
                    if (EventAnalyzed.this.isBackground() && EventAnalyzed.mSdrController != null) {
                        ApsCommon.logI(EventAnalyzed.TAG, "SDR: stop SDR because the package is in background");
                        EventAnalyzed.mSdrController.stopSdrImmediately();
                        EventAnalyzed.this.mHasSetSdr = false;
                    }
                }
            }, 0);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    接下来看下,isBackground():

        public boolean isBackground() {
            if (mActivityManager == null) {
                return false;
            }
            for (RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {// 报错点,在这里,返回list 为空
                if (appProcess.processName.equals(mPkgName) && appProcess.importance != 100) {
                    ApsCommon.logD(TAG, "SDR: The pkg is in Background and pkg: " + mPkgName);
                    return true;
                }
            }
            ApsCommon.logD(TAG, "SDR: The pkg is not in Background and pkg: " + mPkgName);
            return false;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    解决方法
    也是采用hook 方式,拦截IEventAnalyzed 是一个接口,可以考虑动态代理掉setHasOnPaused().

    再结合报错的机型,如下:

    在这里插入图片描述

    关键代码

            else if (method.getName().equals("setHasOnPaused")) {
                          
                                //EventAnalyzed#setHasOnPaused->EventAnalyzed#checkBackground()->EventAnalyzed#isBackground()
                                if (Build.VERSION_CODES.M == Build.VERSION.SDK_INT) {
                                    // 在 华为机型的android 6.0 屏蔽该方法的调用
                                } else {
                                    result = proxy.doRealInvoke(method, args);
                                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    【echarts】06、echarts+vue2 - 雷达图
    【mysql】游标的基本使用
    文件上传时各配置目录优先级详解
    python爬虫之多线程threading、多进程multiprocessing、协程aiohttp 批量下载图片
    SpringSecurity - 密码加密
    「mysql进阶」索引的使用规则、设计原则
    【Python自学笔记】Flask调教方法Internel Server Error
    【UV打印机】墨路之过滤器
    【多线程】阻塞队列 详解
    【RTOS学习】优先级 | Tick | 任务状态 | 空闲任务 | 任务调度
  • 原文地址:https://blog.csdn.net/hexingen/article/details/126600934