处理华为Framework层中curosr和空指针问题(反编译ROM和Hook动态代理)
Posted 新根
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了处理华为Framework层中curosr和空指针问题(反编译ROM和Hook动态代理)相关的知识,希望对你有一定的参考价值。
最近一直忙着解决公司游戏的Bug,但有些问题是顽固分子,许多个迭代都没解决掉,但不处理总觉有一根刺,在扎着肉。
本篇是记录如何处理手机系统ROM中Framework中报错,可以适用不同的手机厂商。
bugly上的问题:
android.database.CursorWindowAllocationException
Cursor window could not be created from binder.
android.database.CursorWindow.<init>(CursorWindow.java:137)
android.database.CursorWindow.<init>(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)
从代码报错点来看是,cursor 过多未关闭,存在泄漏,产生的原因可能是cursor未关闭或者fd 过多或者是内存不足。
因报错点发生在华为ROM的framework层,因此要先考虑获取到对应的framework.dex, 查看代码调用流程,再来确定解决方案。
设备信息:
设备机型 | 系统版本 | ROM |
---|---|---|
WAS-AL00 | Android 8.0.0,level 26 | HuaWei/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;
先来看下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;
HwFrameworkFactory 是一个封装的api 类,用于静态方法/工厂类方式,间接调用各种api。
接下来,继续看下huawei/android/common/HwFrameworkFactoryImpl
类中的getHwNsdImpl()
:
public HwNsdImpl getHwNsdImpl()
return HwNsdImpl.getDefault();
接下来看下android/view/HwNsdImpl
:
public static HwNsdImpl getDefault()
if (mInstance == null)
mInstance = new HwNsdImpl();
return mInstance;
经过一些列的追踪,可以了解到ViewRootImpl对象中调用的是HwNsdImpl中的方法。
接下来看下,isGameProcess()
和isSupportAps()
和adaptPowerSave()
等几个方法。
2.1 华为framework 统计游戏fps 的条件
public boolean isSupportAps()
return SystemProperties.getInt("sys.aps.support", 0) > 0;
从上面代码可知,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();
接下来看下, 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;
从上面代码可知, HwapsWrapper是一个封装api的类, 其真正调用是HwapsFactoryImpl类。
com/huawei/android/hwaps/HwapsFactoryImpl
:
public class HwapsFactoryImpl implements IHwapsFactory
//...
public IEventAnalyzed getEventAnalyzed()
return new EventAnalyzed();
经过一些列的波折,最终调用链是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;
从上面可见,若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);
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);
//.....
接下来看下com/huawei/android/hwaps/OperateExperienceLib
的 saveAPSResult()
:
public void saveAPSResult(int gameType, int maxFPS, int minFPS)
this.mGameType = gameType;
this.mMaxFPS = maxFPS;
this.mMinFPS = minFPS;
if (this.mIsExistInDataBase)
updateAppInfo();
else
insertAppInfo();
这里发生了一点小变故,可能是同样的手机,同个大编号的系统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();
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( 处理华为Framework层中curosr和空指针问题(反编译ROM和Hook动态代理)