Android R设置APP热点模块TetheringManager内存泄漏修复咨询
Android R TetheringManager内存泄漏修复方案
问题概述
在Android R系统的设置APP(热点与网络共享模块)中,使用TetheringManager时存在内存泄漏问题:
TetheringManager构造函数中调用registerTetheringEventCallback注册回调,但未提供对应的反注册逻辑- 性能分析工具检测到
mTetheringEventCallback被TetheringManager持有强引用,导致TetherSettings页面实例无法被GC回收
问题代码分析
原TetheringManager构造函数代码:
@SystemApi(client = MODULE_LIBRARIES) public TetheringManager(@NonNull final Context context, @NonNull Supplier<IBinder> connectorSupplier) { mContext = context; mCallback = new TetheringCallbackInternal(this); mConnectorSupplier = connectorSupplier; final String pkgName = mContext.getOpPackageName(); final IBinder connector = mConnectorSupplier.get(); // If the connector is available on start, do not start a polling thread. This introduces // differences in the thread that sends the oneway binder calls to the service between the // first few seconds after boot and later, but it avoids always having differences between // the first usage of TetheringManager from a process and subsequent usages (so the // difference is only on boot). On boot binder calls may be queued until the service comes // up and be sent from a worker thread; later, they are always sent from the caller thread. // Considering that it's just oneway binder calls, and ordering is preserved, this seems // better than inconsistent behavior persisting after boot. if (connector != null) { mConnector = ITetheringConnector.Stub.asInterface(connector); } else { startPollingForConnector(); } getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName)); }
修复方案
方案1:系统级源码修复(最优解)
修改TetheringManager源码,添加反注册方法并要求调用方主动释放:
- 在
TetheringManager中添加反注册方法:
@SystemApi(client = MODULE_LIBRARIES) public void unregisterTetheringEventCallback() { getConnector(c -> c.unregisterTetheringEventCallback(mCallback)); } // 可选:添加finalize方法作为兜底(注意finalize已过时,仅用于兼容旧逻辑) @Deprecated @Override protected void finalize() throws Throwable { try { unregisterTetheringEventCallback(); } finally { super.finalize(); } }
- 在
TetherSettings的页面销毁生命周期中调用反注册:
@Override protected void onDestroy() { super.onDestroy(); if (mTetheringManager != null) { mTetheringManager.unregisterTetheringEventCallback(); } }
方案2:APP层面反射兼容(无法修改系统源码时使用)
通过反射调用系统内部接口完成反注册,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); if (mTetheringManager != null) { try { // 反射获取mCallback实例 Field callbackField = TetheringManager.class.getDeclaredField("mCallback"); callbackField.setAccessible(true); Object tetheringCallback = callbackField.get(mTetheringManager); // 反射获取mConnector实例 Field connectorField = TetheringManager.class.getDeclaredField("mConnector"); connectorField.setAccessible(true); ITetheringConnector connector = (ITetheringConnector) connectorField.get(mTetheringManager); if (connector != null && tetheringCallback != null) { // 调用反注册接口 connector.unregisterTetheringEventCallback(tetheringCallback); } } catch (NoSuchFieldException | IllegalAccessException | RemoteException e) { // 捕获异常,避免页面崩溃 e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Judy
相关产品推荐
相关产品推荐

